aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am24
-rw-r--r--src/Makefile.bench.include9
-rw-r--r--src/Makefile.qt.include6
-rw-r--r--src/Makefile.qttest.include6
-rw-r--r--src/Makefile.test.include10
-rw-r--r--src/addrdb.cpp21
-rw-r--r--src/addrdb.h8
-rw-r--r--src/addrman.cpp14
-rw-r--r--src/addrman.h25
-rw-r--r--src/arith_uint256.cpp8
-rw-r--r--src/arith_uint256.h4
-rw-r--r--src/base58.cpp195
-rw-r--r--src/base58.h40
-rw-r--r--src/bech32.cpp191
-rw-r--r--src/bech32.h25
-rw-r--r--src/bench/Examples.cpp6
-rw-r--r--src/bench/base58.cpp8
-rw-r--r--src/bench/bench.cpp45
-rw-r--r--src/bench/bench.h36
-rw-r--r--src/bench/bench_bitcoin.cpp12
-rw-r--r--src/bench/ccoins_caching.cpp8
-rw-r--r--src/bench/checkblock.cpp12
-rw-r--r--src/bench/checkqueue.cpp16
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bench/crypto_hash.cpp22
-rw-r--r--src/bench/lockedpool.cpp8
-rw-r--r--src/bench/mempool_eviction.cpp6
-rw-r--r--src/bench/perf.cpp2
-rw-r--r--src/bench/prevector_destructor.cpp4
-rw-r--r--src/bench/rollingbloom.cpp11
-rw-r--r--src/bench/verify_script.cpp12
-rw-r--r--src/bitcoin-cli.cpp154
-rw-r--r--src/bitcoin-tx.cpp82
-rw-r--r--src/bitcoind.cpp36
-rw-r--r--src/blockencodings.cpp20
-rw-r--r--src/blockencodings.h8
-rw-r--r--src/bloom.cpp16
-rw-r--r--src/bloom.h2
-rw-r--r--src/chain.cpp15
-rw-r--r--src/chain.h26
-rw-r--r--src/chainparams.cpp36
-rw-r--r--src/chainparams.h10
-rw-r--r--src/chainparamsbase.cpp8
-rw-r--r--src/checkpoints.cpp11
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/checkqueue.h4
-rw-r--r--src/clientversion.cpp9
-rw-r--r--src/clientversion.h2
-rw-r--r--src/coins.cpp105
-rw-r--r--src/coins.h24
-rw-r--r--src/compat.h14
-rw-r--r--src/compat/byteswap.h10
-rw-r--r--src/compat/endian.h6
-rw-r--r--src/compat/glibc_compat.cpp2
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/compat/strnlen.cpp2
-rw-r--r--src/compressor.cpp8
-rw-r--r--src/compressor.h10
-rw-r--r--src/consensus/consensus.h11
-rw-r--r--src/consensus/merkle.cpp6
-rw-r--r--src/consensus/merkle.h6
-rw-r--r--src/consensus/params.h14
-rw-r--r--src/consensus/tx_verify.cpp92
-rw-r--r--src/consensus/tx_verify.h5
-rw-r--r--src/consensus/validation.h19
-rw-r--r--src/core_io.h4
-rw-r--r--src/core_memusage.h6
-rw-r--r--src/core_read.cpp18
-rw-r--r--src/core_write.cpp35
-rw-r--r--src/crypto/aes.cpp6
-rw-r--r--src/crypto/aes.h10
-rw-r--r--src/crypto/chacha20.cpp4
-rw-r--r--src/crypto/common.h4
-rw-r--r--src/crypto/hmac_sha256.cpp2
-rw-r--r--src/crypto/hmac_sha256.h4
-rw-r--r--src/crypto/hmac_sha512.cpp2
-rw-r--r--src/crypto/hmac_sha512.h2
-rw-r--r--src/crypto/ripemd160.cpp4
-rw-r--r--src/crypto/sha1.cpp4
-rw-r--r--src/crypto/sha256.cpp8
-rw-r--r--src/crypto/sha512.cpp4
-rw-r--r--src/cuckoocache.h8
-rw-r--r--src/dbwrapper.cpp12
-rw-r--r--src/dbwrapper.h20
-rw-r--r--src/fs.cpp2
-rw-r--r--src/hash.cpp7
-rw-r--r--src/hash.h28
-rw-r--r--src/httprpc.cpp41
-rw-r--r--src/httpserver.cpp72
-rw-r--r--src/httpserver.h2
-rw-r--r--src/init.cpp290
-rw-r--r--src/key.cpp11
-rw-r--r--src/key.h15
-rw-r--r--src/keystore.cpp33
-rw-r--r--src/keystore.h64
-rw-r--r--src/limitedmap.h2
-rw-r--r--src/memusage.h2
-rw-r--r--src/merkleblock.cpp43
-rw-r--r--src/merkleblock.h26
-rw-r--r--src/miner.cpp86
-rw-r--r--src/miner.h25
-rw-r--r--src/net.cpp454
-rw-r--r--src/net.h131
-rw-r--r--src/net_processing.cpp1062
-rw-r--r--src/net_processing.h61
-rw-r--r--src/netaddress.cpp12
-rw-r--r--src/netaddress.h14
-rw-r--r--src/netbase.cpp254
-rw-r--r--src/netbase.h16
-rw-r--r--src/netmessagemaker.h6
-rw-r--r--src/noui.cpp6
-rw-r--r--src/policy/feerate.cpp4
-rw-r--r--src/policy/feerate.h12
-rw-r--r--src/policy/fees.cpp51
-rw-r--r--src/policy/fees.h18
-rw-r--r--src/policy/policy.cpp49
-rw-r--r--src/policy/policy.h12
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/pow.cpp10
-rw-r--r--src/pow.h2
-rw-r--r--src/prevector.h6
-rw-r--r--src/primitives/block.cpp10
-rw-r--r--src/primitives/block.h8
-rw-r--r--src/primitives/transaction.cpp16
-rw-r--r--src/primitives/transaction.h12
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h73
-rw-r--r--src/pubkey.cpp3
-rw-r--r--src/pubkey.h10
-rw-r--r--src/qt/addressbookpage.cpp18
-rw-r--r--src/qt/addresstablemodel.cpp32
-rw-r--r--src/qt/askpassphrasedialog.cpp22
-rw-r--r--src/qt/askpassphrasedialog.h1
-rw-r--r--src/qt/bantablemodel.cpp18
-rw-r--r--src/qt/bantablemodel.h2
-rw-r--r--src/qt/bitcoin.cpp52
-rw-r--r--src/qt/bitcoinaddressvalidator.cpp10
-rw-r--r--src/qt/bitcoinamountfield.cpp10
-rw-r--r--src/qt/bitcoinamountfield.h2
-rw-r--r--src/qt/bitcoingui.cpp58
-rw-r--r--src/qt/bitcoingui.h4
-rw-r--r--src/qt/bitcoinunits.cpp4
-rw-r--r--src/qt/bitcoinunits.h2
-rw-r--r--src/qt/callback.h2
-rw-r--r--src/qt/clientmodel.cpp34
-rw-r--r--src/qt/coincontroldialog.cpp43
-rw-r--r--src/qt/coincontroldialog.h8
-rw-r--r--src/qt/coincontroltreewidget.cpp4
-rw-r--r--src/qt/csvmodelwriter.cpp2
-rw-r--r--src/qt/editaddressdialog.cpp8
-rw-r--r--src/qt/forms/askpassphrasedialog.ui7
-rw-r--r--src/qt/forms/coincontroldialog.ui2
-rw-r--r--src/qt/forms/debugwindow.ui2
-rw-r--r--src/qt/forms/editaddressdialog.ui2
-rw-r--r--src/qt/forms/modaloverlay.ui2
-rw-r--r--src/qt/forms/openuridialog.ui2
-rw-r--r--src/qt/forms/optionsdialog.ui16
-rw-r--r--src/qt/forms/receivecoinsdialog.ui24
-rw-r--r--src/qt/forms/receiverequestdialog.ui2
-rw-r--r--src/qt/forms/sendcoinsdialog.ui17
-rw-r--r--src/qt/forms/sendcoinsentry.ui13
-rw-r--r--src/qt/forms/signverifymessagedialog.ui2
-rw-r--r--src/qt/guiutil.cpp124
-rw-r--r--src/qt/guiutil.h11
-rw-r--r--src/qt/intro.cpp21
-rw-r--r--src/qt/macdockiconhandler.mm8
-rw-r--r--src/qt/macnotificationhandler.h7
-rw-r--r--src/qt/macnotificationhandler.mm16
-rw-r--r--src/qt/modaloverlay.cpp34
-rw-r--r--src/qt/modaloverlay.h2
-rw-r--r--src/qt/networkstyle.cpp6
-rw-r--r--src/qt/notificator.cpp73
-rw-r--r--src/qt/notificator.h5
-rw-r--r--src/qt/openuridialog.cpp8
-rw-r--r--src/qt/optionsdialog.cpp26
-rw-r--r--src/qt/optionsmodel.cpp154
-rw-r--r--src/qt/optionsmodel.h19
-rw-r--r--src/qt/overviewpage.cpp28
-rw-r--r--src/qt/overviewpage.h2
-rw-r--r--src/qt/paymentrequestplus.cpp9
-rw-r--r--src/qt/paymentrequestplus.h4
-rw-r--r--src/qt/paymentserver.cpp40
-rw-r--r--src/qt/paymentserver.h8
-rw-r--r--src/qt/peertablemodel.cpp32
-rw-r--r--src/qt/peertablemodel.h10
-rw-r--r--src/qt/platformstyle.cpp6
-rw-r--r--src/qt/qvalidatedlineedit.cpp6
-rw-r--r--src/qt/qvaluecombobox.cpp2
-rw-r--r--src/qt/receivecoinsdialog.cpp46
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/receiverequestdialog.cpp15
-rw-r--r--src/qt/receiverequestdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp12
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/rpcconsole.cpp91
-rw-r--r--src/qt/rpcconsole.h7
-rw-r--r--src/qt/sendcoinsdialog.cpp106
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/sendcoinsentry.cpp31
-rw-r--r--src/qt/sendcoinsentry.h6
-rw-r--r--src/qt/signverifymessagedialog.cpp46
-rw-r--r--src/qt/splashscreen.cpp50
-rw-r--r--src/qt/splashscreen.h4
-rw-r--r--src/qt/test/compattests.cpp6
-rw-r--r--src/qt/test/paymentservertests.cpp34
-rw-r--r--src/qt/test/paymentservertests.h4
-rw-r--r--src/qt/test/rpcnestedtests.cpp38
-rw-r--r--src/qt/test/rpcnestedtests.h7
-rw-r--r--src/qt/test/test_main.cpp24
-rw-r--r--src/qt/test/uritests.cpp6
-rw-r--r--src/qt/test/wallettests.cpp116
-rw-r--r--src/qt/trafficgraphwidget.cpp4
-rw-r--r--src/qt/transactiondesc.cpp43
-rw-r--r--src/qt/transactiondescdialog.cpp6
-rw-r--r--src/qt/transactionfilterproxy.cpp21
-rw-r--r--src/qt/transactionfilterproxy.h6
-rw-r--r--src/qt/transactionrecord.cpp20
-rw-r--r--src/qt/transactionrecord.h6
-rw-r--r--src/qt/transactiontablemodel.cpp42
-rw-r--r--src/qt/transactiontablemodel.h4
-rw-r--r--src/qt/transactionview.cpp66
-rw-r--r--src/qt/transactionview.h8
-rw-r--r--src/qt/utilitydialog.cpp24
-rw-r--r--src/qt/utilitydialog.h2
-rw-r--r--src/qt/walletframe.cpp8
-rw-r--r--src/qt/walletmodel.cpp122
-rw-r--r--src/qt/walletmodel.h8
-rw-r--r--src/qt/walletmodeltransaction.cpp22
-rw-r--r--src/qt/walletmodeltransaction.h12
-rw-r--r--src/qt/walletview.cpp40
-rw-r--r--src/qt/walletview.h2
-rw-r--r--src/qt/winshutdownmonitor.cpp6
-rw-r--r--src/random.cpp18
-rw-r--r--src/random.h8
-rw-r--r--src/rest.cpp68
-rw-r--r--src/reverse_iterator.h2
-rw-r--r--src/rpc/blockchain.cpp270
-rw-r--r--src/rpc/client.cpp15
-rw-r--r--src/rpc/mining.cpp113
-rw-r--r--src/rpc/mining.h2
-rw-r--r--src/rpc/misc.cpp305
-rw-r--r--src/rpc/net.cpp92
-rw-r--r--src/rpc/protocol.cpp57
-rw-r--r--src/rpc/protocol.h7
-rw-r--r--src/rpc/rawtransaction.cpp218
-rw-r--r--src/rpc/safemode.cpp14
-rw-r--r--src/rpc/safemode.h12
-rw-r--r--src/rpc/server.cpp53
-rw-r--r--src/rpc/server.h14
-rw-r--r--src/scheduler.cpp8
-rw-r--r--src/scheduler.h6
-rw-r--r--src/script/bitcoinconsensus.cpp10
-rw-r--r--src/script/bitcoinconsensus.h2
-rw-r--r--src/script/interpreter.cpp46
-rw-r--r--src/script/interpreter.h30
-rw-r--r--src/script/ismine.cpp14
-rw-r--r--src/script/ismine.h2
-rw-r--r--src/script/script.cpp6
-rw-r--r--src/script/script.h13
-rw-r--r--src/script/script_error.cpp4
-rw-r--r--src/script/sigcache.cpp14
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.cpp16
-rw-r--r--src/script/sign.h6
-rw-r--r--src/script/standard.cpp64
-rw-r--r--src/script/standard.h106
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.h10
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.h10
-rw-r--r--src/secp256k1/include/secp256k1.h23
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h16
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h16
-rw-r--r--src/secp256k1/sage/group_prover.sage2
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s2
-rw-r--r--src/secp256k1/src/basic-config.h9
-rw-r--r--src/secp256k1/src/bench.h6
-rw-r--r--src/secp256k1/src/ecdsa.h6
-rw-r--r--src/secp256k1/src/ecdsa_impl.h8
-rw-r--r--src/secp256k1/src/eckey.h6
-rw-r--r--src/secp256k1/src/eckey_impl.h17
-rw-r--r--src/secp256k1/src/ecmult.h6
-rw-r--r--src/secp256k1/src/ecmult_const.h6
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h13
-rw-r--r--src/secp256k1/src/ecmult_gen.h6
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h6
-rw-r--r--src/secp256k1/src/ecmult_impl.h6
-rw-r--r--src/secp256k1/src/field.h6
-rw-r--r--src/secp256k1/src/field_10x26.h7
-rw-r--r--src/secp256k1/src/field_10x26_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52.h6
-rw-r--r--src/secp256k1/src/field_5x52_asm_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h6
-rw-r--r--src/secp256k1/src/field_impl.h6
-rw-r--r--src/secp256k1/src/group.h6
-rw-r--r--src/secp256k1/src/group_impl.h6
-rw-r--r--src/secp256k1/src/hash.h6
-rw-r--r--src/secp256k1/src/hash_impl.h6
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h6
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h6
-rwxr-xr-xsrc/secp256k1/src/modules/recovery/main_impl.h6
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h6
-rw-r--r--src/secp256k1/src/num.h6
-rw-r--r--src/secp256k1/src/num_gmp.h6
-rw-r--r--src/secp256k1/src/num_gmp_impl.h6
-rw-r--r--src/secp256k1/src/num_impl.h6
-rw-r--r--src/secp256k1/src/scalar.h6
-rw-r--r--src/secp256k1/src/scalar_4x64.h6
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h6
-rw-r--r--src/secp256k1/src/scalar_8x32.h6
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h6
-rw-r--r--src/secp256k1/src/scalar_impl.h6
-rw-r--r--src/secp256k1/src/scalar_low.h6
-rw-r--r--src/secp256k1/src/scalar_low_impl.h6
-rw-r--r--src/secp256k1/src/testrand.h6
-rw-r--r--src/secp256k1/src/testrand_impl.h6
-rw-r--r--src/secp256k1/src/util.h6
-rw-r--r--src/serialize.h14
-rw-r--r--src/streams.h40
-rw-r--r--src/support/allocators/secure.h12
-rw-r--r--src/support/allocators/zeroafterfree.h10
-rw-r--r--src/support/cleanse.cpp36
-rw-r--r--src/support/lockedpool.cpp6
-rw-r--r--src/support/lockedpool.h16
-rw-r--r--src/sync.cpp42
-rw-r--r--src/sync.h73
-rw-r--r--src/test/DoS_tests.cpp228
-rw-r--r--src/test/README.md7
-rw-r--r--src/test/addrman_tests.cpp12
-rw-r--r--src/test/allocator_tests.cpp6
-rw-r--r--src/test/amount_tests.cpp6
-rw-r--r--src/test/arith_uint256_tests.cpp8
-rw-r--r--src/test/base32_tests.cpp4
-rw-r--r--src/test/base58_tests.cpp175
-rw-r--r--src/test/base64_tests.cpp4
-rw-r--r--src/test/bech32_tests.cpp67
-rw-r--r--src/test/bip32_tests.cpp16
-rw-r--r--src/test/blockencodings_tests.cpp19
-rw-r--r--src/test/bloom_tests.cpp42
-rw-r--r--src/test/bswap_tests.cpp4
-rw-r--r--src/test/checkqueue_tests.cpp47
-rw-r--r--src/test/coins_tests.cpp46
-rw-r--r--src/test/compress_tests.cpp6
-rw-r--r--src/test/crypto_tests.cpp107
-rw-r--r--src/test/cuckoocache_tests.cpp8
-rw-r--r--src/test/data/base58_keys_invalid.json30
-rw-r--r--src/test/data/base58_keys_valid.json679
-rw-r--r--src/test/data/script_tests.json2
-rw-r--r--src/test/data/tx_invalid.json2
-rw-r--r--src/test/data/tx_valid.json2
-rw-r--r--src/test/dbwrapper_tests.cpp36
-rw-r--r--src/test/getarg_tests.cpp6
-rw-r--r--src/test/hash_tests.cpp6
-rw-r--r--src/test/key_tests.cpp41
-rw-r--r--src/test/limitedmap_tests.cpp4
-rw-r--r--src/test/main_tests.cpp8
-rw-r--r--src/test/mempool_tests.cpp16
-rw-r--r--src/test/merkle_tests.cpp4
-rw-r--r--src/test/merkleblock_tests.cpp78
-rw-r--r--src/test/miner_tests.cpp70
-rw-r--r--src/test/multisig_tests.cpp111
-rw-r--r--src/test/net_tests.cpp18
-rw-r--r--src/test/netbase_tests.cpp6
-rw-r--r--src/test/pmt_tests.cpp16
-rw-r--r--src/test/policyestimator_tests.cpp12
-rw-r--r--src/test/pow_tests.cpp12
-rw-r--r--src/test/prevector_tests.cpp14
-rw-r--r--src/test/raii_event_tests.cpp4
-rw-r--r--src/test/random_tests.cpp4
-rw-r--r--src/test/reverselock_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp12
-rw-r--r--src/test/sanity_tests.cpp6
-rw-r--r--src/test/scheduler_tests.cpp6
-rw-r--r--src/test/script_P2SH_tests.cpp25
-rw-r--r--src/test/script_standard_tests.cpp741
-rw-r--r--src/test/script_tests.cpp56
-rw-r--r--src/test/scriptnum10.h2
-rw-r--r--src/test/scriptnum_tests.cpp14
-rw-r--r--src/test/serialize_tests.cpp8
-rw-r--r--src/test/sighash_tests.cpp30
-rw-r--r--src/test/sigopcount_tests.cpp16
-rw-r--r--src/test/skiplist_tests.cpp10
-rw-r--r--src/test/streams_tests.cpp6
-rw-r--r--src/test/test_bitcoin.cpp87
-rw-r--r--src/test/test_bitcoin.h34
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp103
-rw-r--r--src/test/test_bitcoin_main.cpp10
-rw-r--r--src/test/testutil.cpp15
-rw-r--r--src/test/testutil.h15
-rw-r--r--src/test/timedata_tests.cpp4
-rw-r--r--src/test/torcontrol_tests.cpp4
-rw-r--r--src/test/transaction_tests.cpp39
-rw-r--r--src/test/txvalidation_tests.cpp61
-rw-r--r--src/test/txvalidationcache_tests.cpp77
-rw-r--r--src/test/uint256_tests.cpp8
-rw-r--r--src/test/univalue_tests.cpp2
-rw-r--r--src/test/util_tests.cpp39
-rw-r--r--src/test/versionbits_tests.cpp35
-rw-r--r--src/threadinterrupt.cpp2
-rw-r--r--src/timedata.cpp16
-rw-r--r--src/tinyformat.h22
-rw-r--r--src/torcontrol.cpp22
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txdb.cpp26
-rw-r--r--src/txdb.h28
-rw-r--r--src/txmempool.cpp61
-rw-r--r--src/txmempool.h50
-rw-r--r--src/ui_interface.cpp4
-rw-r--r--src/ui_interface.h10
-rw-r--r--src/uint256.cpp6
-rw-r--r--src/uint256.h6
-rw-r--r--src/undo.h12
-rw-r--r--src/univalue/Makefile.am29
-rw-r--r--src/univalue/README7
-rw-r--r--src/univalue/README.md32
-rw-r--r--src/univalue/configure.ac6
-rw-r--r--src/univalue/include/univalue.h34
-rw-r--r--src/univalue/lib/univalue.cpp193
-rw-r--r--src/univalue/lib/univalue_get.cpp147
-rw-r--r--src/univalue/lib/univalue_read.cpp72
-rw-r--r--src/univalue/lib/univalue_utffilter.h44
-rw-r--r--src/univalue/lib/univalue_write.cpp2
-rw-r--r--src/univalue/test/.gitignore4
-rw-r--r--src/univalue/test/fail1.json2
-rw-r--r--src/univalue/test/fail42.jsonbin0 -> 37 bytes
-rw-r--r--src/univalue/test/fail44.json1
-rw-r--r--src/univalue/test/no_nul.cpp8
-rw-r--r--src/univalue/test/object.cpp395
-rw-r--r--src/univalue/test/round3.json1
-rw-r--r--src/univalue/test/round4.json1
-rw-r--r--src/univalue/test/round5.json1
-rw-r--r--src/univalue/test/round6.json1
-rw-r--r--src/univalue/test/round7.json1
-rw-r--r--src/univalue/test/test_json.cpp24
-rw-r--r--src/univalue/test/unitester.cpp7
-rw-r--r--src/util.cpp95
-rw-r--r--src/util.h49
-rw-r--r--src/utilmoneystr.cpp8
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/utilstrencodings.cpp17
-rw-r--r--src/utilstrencodings.h30
-rw-r--r--src/utiltime.cpp4
-rw-r--r--src/validation.cpp945
-rw-r--r--src/validation.h77
-rw-r--r--src/validationinterface.cpp72
-rw-r--r--src/validationinterface.h70
-rw-r--r--src/versionbits.cpp18
-rw-r--r--src/versionbits.h2
-rw-r--r--src/wallet/coincontrol.h8
-rw-r--r--src/wallet/crypter.cpp162
-rw-r--r--src/wallet/crypter.h62
-rw-r--r--src/wallet/db.cpp144
-rw-r--r--src/wallet/db.h27
-rw-r--r--src/wallet/feebumper.cpp246
-rw-r--r--src/wallet/feebumper.h67
-rw-r--r--src/wallet/fees.cpp89
-rw-r--r--src/wallet/fees.h34
-rw-r--r--src/wallet/init.cpp295
-rw-r--r--src/wallet/init.h43
-rw-r--r--src/wallet/rpcdump.cpp152
-rw-r--r--src/wallet/rpcwallet.cpp849
-rw-r--r--src/wallet/rpcwallet.h3
-rw-r--r--src/wallet/test/accounting_tests.cpp24
-rw-r--r--src/wallet/test/crypto_tests.cpp141
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp17
-rw-r--r--src/wallet/test/wallet_test_fixture.h8
-rw-r--r--src/wallet/test/wallet_tests.cpp44
-rw-r--r--src/wallet/wallet.cpp798
-rw-r--r--src/wallet/wallet.h115
-rw-r--r--src/wallet/walletdb.cpp93
-rw-r--r--src/wallet/walletdb.h23
-rw-r--r--src/wallet/walletutil.cpp27
-rw-r--r--src/wallet/walletutil.h13
-rw-r--r--src/warnings.cpp8
-rw-r--r--src/zmq/zmqabstractnotifier.cpp4
-rw-r--r--src/zmq/zmqabstractnotifier.h4
-rw-r--r--src/zmq/zmqconfig.h6
-rw-r--r--src/zmq/zmqnotificationinterface.cpp22
-rw-r--r--src/zmq/zmqnotificationinterface.h4
-rw-r--r--src/zmq/zmqpublishnotifier.cpp18
-rw-r--r--src/zmq/zmqpublishnotifier.h2
481 files changed, 11441 insertions, 7489 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f7abab482e..4b65774fc6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,8 +18,7 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
-BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
@@ -79,6 +78,7 @@ BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
base58.h \
+ bech32.h \
bloom.h \
blockencodings.h \
chain.h \
@@ -130,6 +130,7 @@ BITCOIN_CORE_H = \
rpc/client.h \
rpc/mining.h \
rpc/protocol.h \
+ rpc/safemode.h \
rpc/server.h \
rpc/register.h \
scheduler.h \
@@ -162,9 +163,12 @@ BITCOIN_CORE_H = \
wallet/crypter.h \
wallet/db.h \
wallet/feebumper.h \
+ wallet/fees.h \
+ wallet/init.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
+ wallet/walletutil.h \
warnings.h \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
@@ -208,6 +212,7 @@ libbitcoin_server_a_SOURCES = \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
+ rpc/safemode.cpp \
rpc/server.cpp \
script/sigcache.cpp \
script/ismine.cpp \
@@ -239,14 +244,17 @@ libbitcoin_wallet_a_SOURCES = \
wallet/crypter.cpp \
wallet/db.cpp \
wallet/feebumper.cpp \
+ wallet/fees.cpp \
+ wallet/init.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
+ wallet/walletutil.cpp \
$(BITCOIN_CORE_H)
# crypto primitives library
-crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
+crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
crypto/aes.cpp \
@@ -267,7 +275,7 @@ crypto_libbitcoin_crypto_a_SOURCES = \
crypto/sha512.cpp \
crypto/sha512.h
-if EXPERIMENTAL_ASM
+if USE_ASM
crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
endif
@@ -311,6 +319,7 @@ libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
base58.cpp \
+ bech32.cpp \
chainparams.cpp \
coins.cpp \
compressor.cpp \
@@ -469,8 +478,7 @@ CLEANFILES += univalue/*.gcda univalue/*.gcno
CLEANFILES += wallet/*.gcda wallet/*.gcno
CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
CLEANFILES += zmq/*.gcda zmq/*.gcno
-
-DISTCLEANFILES = obj/build.h
+CLEANFILES += obj/build.h
EXTRA_DIST = $(CTAES_DIST)
@@ -494,10 +502,6 @@ clean-local:
## FIXME: How to get the appropriate modulename_CPPFLAGS in here?
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
-.mm.o:
- $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<
-
check-symbols: $(bin_PROGRAMS)
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat..."
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 2b1f70b25b..8e2e587d32 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -6,11 +6,12 @@ bin_PROGRAMS += bench/bench_bitcoin
BENCH_SRCDIR = bench
BENCH_BINARY = bench/bench_bitcoin$(EXEEXT)
-RAW_TEST_FILES = \
+RAW_BENCH_FILES = \
bench/data/block413567.raw
-GENERATED_TEST_FILES = $(RAW_TEST_FILES:.raw=.raw.h)
+GENERATED_BENCH_FILES = $(RAW_BENCH_FILES:.raw=.raw.h)
bench_bench_bitcoin_SOURCES = \
+ $(RAW_BENCH_FILES) \
bench/bench_bitcoin.cpp \
bench/bench.cpp \
bench/bench.h \
@@ -28,7 +29,7 @@ bench_bench_bitcoin_SOURCES = \
bench/perf.h \
bench/prevector_destructor.cpp
-nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
+nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -56,7 +57,7 @@ endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_TEST_FILES)
+CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
CLEANFILES += $(CLEAN_BITCOIN_BENCH)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index e4b64c1ca7..0bdde06772 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -362,12 +362,12 @@ RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png)
BITCOIN_RC = qt/res/bitcoin-qt-res.rc
-BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \
- -I$(builddir)/qt/forms -DQT_NO_KEYWORDS
+BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS
qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
+qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
@@ -438,7 +438,7 @@ $(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin $< | \
$(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
-CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno
+CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_bitcoin_locale.qrc
CLEANFILES += $(CLEAN_QT)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 02f30bc952..ea2ed17472 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -25,12 +25,10 @@ TEST_QT_H = \
qt/test/wallettests.h
TEST_BITCOIN_CPP = \
- test/test_bitcoin.cpp \
- test/testutil.cpp
+ test/test_bitcoin.cpp
TEST_BITCOIN_H = \
- test/test_bitcoin.h \
- test/testutil.h
+ test/test_bitcoin.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 6415b3d2e3..06175be3fc 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -31,6 +31,7 @@ BITCOIN_TESTS =\
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
+ test/bech32_tests.cpp \
test/bip32_tests.cpp \
test/blockencodings_tests.cpp \
test/bloom_tests.cpp \
@@ -49,6 +50,7 @@ BITCOIN_TESTS =\
test/main_tests.cpp \
test/mempool_tests.cpp \
test/merkle_tests.cpp \
+ test/merkleblock_tests.cpp \
test/miner_tests.cpp \
test/multisig_tests.cpp \
test/net_tests.cpp \
@@ -65,6 +67,7 @@ BITCOIN_TESTS =\
test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
+ test/script_standard_tests.cpp \
test/scriptnum_tests.cpp \
test/serialize_tests.cpp \
test/sighash_tests.cpp \
@@ -74,11 +77,10 @@ BITCOIN_TESTS =\
test/test_bitcoin.cpp \
test/test_bitcoin.h \
test/test_bitcoin_main.cpp \
- test/testutil.cpp \
- test/testutil.h \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
+ test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
test/versionbits_tests.cpp \
test/uint256_tests.cpp \
@@ -95,7 +97,7 @@ BITCOIN_TESTS += \
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
+test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD =
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
@@ -148,7 +150,7 @@ bitcoin_test_clean : FORCE
check-local:
@echo "Running test/util/bitcoin-util-test.py..."
- $(top_builddir)/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/addrdb.cpp b/src/addrdb.cpp
index 7f85c16585..7d7f34863d 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -3,17 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrdb.h"
-
-#include "addrman.h"
-#include "chainparams.h"
-#include "clientversion.h"
-#include "fs.h"
-#include "hash.h"
-#include "random.h"
-#include "streams.h"
-#include "tinyformat.h"
-#include "util.h"
+#include <addrdb.h>
+
+#include <addrman.h>
+#include <chainparams.h>
+#include <clientversion.h>
+#include <hash.h>
+#include <random.h>
+#include <streams.h>
+#include <tinyformat.h>
+#include <util.h>
namespace {
diff --git a/src/addrdb.h b/src/addrdb.h
index 6cb36dfac4..098da4240e 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_ADDRDB_H
#define BITCOIN_ADDRDB_H
-#include "fs.h"
-#include "serialize.h"
+#include <fs.h>
+#include <serialize.h>
#include <string>
#include <map>
@@ -37,7 +37,7 @@ public:
SetNull();
}
- CBanEntry(int64_t nCreateTimeIn)
+ explicit CBanEntry(int64_t nCreateTimeIn)
{
SetNull();
nCreateTime = nCreateTimeIn;
@@ -61,7 +61,7 @@ public:
banReason = BanReasonUnknown;
}
- std::string banReasonToString()
+ std::string banReasonToString() const
{
switch (banReason) {
case BanReasonNodeMisbehaving:
diff --git a/src/addrman.cpp b/src/addrman.cpp
index a56bb4f9c1..372cac8483 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrman.h"
+#include <addrman.h>
-#include "hash.h"
-#include "serialize.h"
-#include "streams.h"
+#include <hash.h>
+#include <serialize.h>
+#include <streams.h>
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
@@ -390,9 +390,9 @@ int CAddrMan::Check_()
if (vRandom.size() != nTried + nNew)
return -7;
- for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- int n = (*it).first;
- CAddrInfo& info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ int n = entry.first;
+ const CAddrInfo& info = entry.second;
if (info.fInTried) {
if (!info.nLastSuccess)
return -1;
diff --git a/src/addrman.h b/src/addrman.h
index 547088aedf..ea289d508c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_ADDRMAN_H
#define BITCOIN_ADDRMAN_H
-#include "netaddress.h"
-#include "protocol.h"
-#include "random.h"
-#include "sync.h"
-#include "timedata.h"
-#include "util.h"
+#include <netaddress.h>
+#include <protocol.h>
+#include <random.h>
+#include <sync.h>
+#include <timedata.h>
+#include <util.h>
#include <map>
#include <set>
@@ -313,9 +313,9 @@ public:
s << nUBuckets;
std::map<int, int> mapUnkIds;
int nIds = 0;
- for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- mapUnkIds[(*it).first] = nIds;
- const CAddrInfo &info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ mapUnkIds[entry.first] = nIds;
+ const CAddrInfo &info = entry.second;
if (info.nRefCount) {
assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
@@ -323,8 +323,8 @@ public:
}
}
nIds = 0;
- for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
- const CAddrInfo &info = (*it).second;
+ for (const auto& entry : mapInfo) {
+ const CAddrInfo &info = entry.second;
if (info.fInTried) {
assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
@@ -455,6 +455,7 @@ public:
void Clear()
{
+ LOCK(cs);
std::vector<int>().swap(vRandom);
nKey = GetRandHash();
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
@@ -472,6 +473,8 @@ public:
nTried = 0;
nNew = 0;
nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
+ mapInfo.clear();
+ mapAddr.clear();
}
CAddrMan()
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index b4952af6f4..738224fb70 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "arith_uint256.h"
+#include <arith_uint256.h>
-#include "uint256.h"
-#include "utilstrencodings.h"
-#include "crypto/common.h"
+#include <uint256.h>
+#include <utilstrencodings.h>
+#include <crypto/common.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 6223e4afeb..1009fe1cc8 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -25,7 +25,7 @@ template<unsigned int BITS>
class base_uint
{
protected:
- enum { WIDTH=BITS/32 };
+ static constexpr int WIDTH = BITS / 32;
uint32_t pn[WIDTH];
public:
@@ -250,7 +250,7 @@ public:
uint64_t GetLow64() const
{
- assert(WIDTH >= 2);
+ static_assert(WIDTH >= 2, "Assertion WIDTH >= 2 failed (WIDTH = BITS / 32). BITS is a template parameter.");
return pn[0] | (uint64_t)pn[1] << 32;
}
};
diff --git a/src/base58.cpp b/src/base58.cpp
index c70e358ebb..cd087e7997 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -2,19 +2,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
+#include <base58.h>
-#include "hash.h"
-#include "uint256.h"
+#include <bech32.h>
+#include <hash.h>
+#include <script/script.h>
+#include <uint256.h>
+#include <utilstrencodings.h>
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <vector>
-#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
+#include <algorithm>
+#include <assert.h>
+#include <string.h>
+
+
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@@ -136,7 +139,7 @@ bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
}
// 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) {
+ if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
vchRet.clear();
return false;
}
@@ -212,79 +215,113 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const
namespace
{
-class CBitcoinAddressVisitor : public boost::static_visitor<bool>
+class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
- CBitcoinAddress* addr;
+ const CChainParams& m_params;
public:
- CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
-
- bool operator()(const CKeyID& id) const { return addr->Set(id); }
- bool operator()(const CScriptID& id) const { return addr->Set(id); }
- bool operator()(const CNoDestination& no) const { return false; }
-};
-
-} // namespace
-
-bool CBitcoinAddress::Set(const CKeyID& id)
-{
- SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
- return true;
-}
+ DestinationEncoder(const CChainParams& params) : m_params(params) {}
-bool CBitcoinAddress::Set(const CScriptID& id)
-{
- SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
- return true;
-}
+ std::string operator()(const CKeyID& id) const
+ {
+ std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::Set(const CTxDestination& dest)
-{
- return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
-}
+ std::string operator()(const CScriptID& id) const
+ {
+ std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::IsValid() const
-{
- return IsValid(Params());
-}
+ std::string operator()(const WitnessV0KeyHash& id) const
+ {
+ std::vector<unsigned char> data = {0};
+ ConvertBits<8, 5, true>(data, id.begin(), id.end());
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-bool CBitcoinAddress::IsValid(const CChainParams& params) const
-{
- bool fCorrectSize = vchData.size() == 20;
- bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
- vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
- return fCorrectSize && fKnownVersion;
-}
+ std::string operator()(const WitnessV0ScriptHash& id) const
+ {
+ std::vector<unsigned char> data = {0};
+ ConvertBits<8, 5, true>(data, id.begin(), id.end());
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-CTxDestination CBitcoinAddress::Get() const
-{
- if (!IsValid())
- return CNoDestination();
- uint160 id;
- memcpy(&id, vchData.data(), 20);
- if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return CKeyID(id);
- else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
- return CScriptID(id);
- else
- return CNoDestination();
-}
+ std::string operator()(const WitnessUnknown& id) const
+ {
+ if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
+ return {};
+ }
+ std::vector<unsigned char> data = {(unsigned char)id.version};
+ ConvertBits<8, 5, true>(data, id.program, id.program + id.length);
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
-{
- if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return false;
- uint160 id;
- memcpy(&id, vchData.data(), 20);
- keyID = CKeyID(id);
- return true;
-}
+ std::string operator()(const CNoDestination& no) const { return {}; }
+};
-bool CBitcoinAddress::IsScript() const
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
- return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ std::vector<unsigned char> data;
+ uint160 hash;
+ if (DecodeBase58Check(str, data)) {
+ // base58-encoded Bitcoin addresses.
+ // Public-key-hash-addresses have version 0 (or 111 testnet).
+ // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
+ const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
+ std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
+ return CKeyID(hash);
+ }
+ // Script-hash-addresses have version 5 (or 196 testnet).
+ // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
+ const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
+ std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
+ return CScriptID(hash);
+ }
+ }
+ data.clear();
+ auto bech = bech32::Decode(str);
+ if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
+ // Bech32 decoding
+ int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
+ // The rest of the symbols are converted witness program bytes.
+ if (ConvertBits<5, 8, false>(data, bech.second.begin() + 1, bech.second.end())) {
+ if (version == 0) {
+ {
+ WitnessV0KeyHash keyid;
+ if (data.size() == keyid.size()) {
+ std::copy(data.begin(), data.end(), keyid.begin());
+ return keyid;
+ }
+ }
+ {
+ WitnessV0ScriptHash scriptid;
+ if (data.size() == scriptid.size()) {
+ std::copy(data.begin(), data.end(), scriptid.begin());
+ return scriptid;
+ }
+ }
+ return CNoDestination();
+ }
+ if (version > 16 || data.size() < 2 || data.size() > 40) {
+ return CNoDestination();
+ }
+ WitnessUnknown unk;
+ unk.version = version;
+ std::copy(data.begin(), data.end(), unk.program);
+ unk.length = data.size();
+ return unk;
+ }
+ }
+ return CNoDestination();
}
+} // namespace
void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
@@ -318,3 +355,23 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
+
+std::string EncodeDestination(const CTxDestination& dest)
+{
+ return boost::apply_visitor(DestinationEncoder(Params()), dest);
+}
+
+CTxDestination DecodeDestination(const std::string& str)
+{
+ return DecodeDestination(str, Params());
+}
+
+bool IsValidDestinationString(const std::string& str, const CChainParams& params)
+{
+ return IsValidDestination(DecodeDestination(str, params));
+}
+
+bool IsValidDestinationString(const std::string& str)
+{
+ return IsValidDestinationString(str, Params());
+}
diff --git a/src/base58.h b/src/base58.h
index db12208f74..fee79f02bf 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -14,12 +14,11 @@
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H
-#include "chainparams.h"
-#include "key.h"
-#include "pubkey.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "support/allocators/zeroafterfree.h"
+#include <chainparams.h>
+#include <key.h>
+#include <pubkey.h>
+#include <script/standard.h>
+#include <support/allocators/zeroafterfree.h>
#include <string>
#include <vector>
@@ -95,30 +94,6 @@ public:
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
-/** base58-encoded Bitcoin addresses.
- * Public-key-hash-addresses have version 0 (or 111 testnet).
- * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
- * Script-hash-addresses have version 5 (or 196 testnet).
- * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
- */
-class CBitcoinAddress : public CBase58Data {
-public:
- bool Set(const CKeyID &id);
- bool Set(const CScriptID &id);
- bool Set(const CTxDestination &dest);
- bool IsValid() const;
- bool IsValid(const CChainParams &params) const;
-
- CBitcoinAddress() {}
- CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
- CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
- CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
-
- CTxDestination Get() const;
- bool GetKeyID(CKeyID &keyID) const;
- bool IsScript() const;
-};
-
/**
* A base58-encoded secret key
*/
@@ -167,4 +142,9 @@ public:
typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;
+std::string EncodeDestination(const CTxDestination& dest);
+CTxDestination DecodeDestination(const std::string& str);
+bool IsValidDestinationString(const std::string& str);
+bool IsValidDestinationString(const std::string& str, const CChainParams& params);
+
#endif // BITCOIN_BASE58_H
diff --git a/src/bech32.cpp b/src/bech32.cpp
new file mode 100644
index 0000000000..274782e467
--- /dev/null
+++ b/src/bech32.cpp
@@ -0,0 +1,191 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bech32.h>
+
+namespace
+{
+
+typedef std::vector<uint8_t> data;
+
+/** The Bech32 character set for encoding. */
+const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+
+/** The Bech32 character set for decoding. */
+const int8_t CHARSET_REV[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
+};
+
+/** Concatenate two byte arrays. */
+data Cat(data x, const data& y)
+{
+ x.insert(x.end(), y.begin(), y.end());
+ return x;
+}
+
+/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
+ * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
+ * bits correspond to earlier values. */
+uint32_t PolyMod(const data& v)
+{
+ // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
+ // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
+ // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
+ // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
+
+ // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
+ // v(x) mod g(x), where g(x) is the Bech32 generator,
+ // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
+ // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
+ // window of 1023 characters. Among the various possible BCH codes, one was selected to in
+ // fact guarantee detection of up to 4 errors within a window of 89 characters.
+
+ // Note that the coefficients are elements of GF(32), here represented as decimal numbers
+ // between {}. In this finite field, addition is just XOR of the corresponding numbers. For
+ // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
+ // treating the bits of values themselves as coefficients of a polynomial over a smaller field,
+ // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
+ // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
+ // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
+
+ // During the course of the loop below, `c` contains the bitpacked coefficients of the
+ // polynomial constructed from just the values of v that were processed so far, mod g(x). In
+ // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
+ // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
+ // for `c`.
+ uint32_t c = 1;
+ for (auto v_i : v) {
+ // We want to update `c` to correspond to a polynomial with one extra term. If the initial
+ // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
+ // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
+ // process. Simplifying:
+ // c'(x) = (f(x) * x + v_i) mod g(x)
+ // ((f(x) mod g(x)) * x + v_i) mod g(x)
+ // (c(x) * x + v_i) mod g(x)
+ // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
+ // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
+ // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
+ // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
+ // If we call (x^6 mod g(x)) = k(x), this can be written as
+ // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
+
+ // First, determine the value of c0:
+ uint8_t c0 = c >> 25;
+
+ // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
+ c = ((c & 0x1ffffff) << 5) ^ v_i;
+
+ // Finally, for each set bit n in c0, conditionally add {2^n}k(x):
+ if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
+ if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
+ if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
+ if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
+ if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
+ }
+ return c;
+}
+
+/** Convert to lower case. */
+inline unsigned char LowerCase(unsigned char c)
+{
+ return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
+}
+
+/** Expand a HRP for use in checksum computation. */
+data ExpandHRP(const std::string& hrp)
+{
+ data ret;
+ ret.reserve(hrp.size() + 90);
+ ret.resize(hrp.size() * 2 + 1);
+ for (size_t i = 0; i < hrp.size(); ++i) {
+ unsigned char c = hrp[i];
+ ret[i] = c >> 5;
+ ret[i + hrp.size() + 1] = c & 0x1f;
+ }
+ ret[hrp.size()] = 0;
+ return ret;
+}
+
+/** Verify a checksum. */
+bool VerifyChecksum(const std::string& hrp, const data& values)
+{
+ // PolyMod computes what value to xor into the final values to make the checksum 0. However,
+ // if we required that the checksum was 0, it would be the case that appending a 0 to a valid
+ // list of values would result in a new valid list. For that reason, Bech32 requires the
+ // resulting checksum to be 1 instead.
+ return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
+}
+
+/** Create a checksum. */
+data CreateChecksum(const std::string& hrp, const data& values)
+{
+ data enc = Cat(ExpandHRP(hrp), values);
+ enc.resize(enc.size() + 6); // Append 6 zeroes
+ uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
+ data ret(6);
+ for (size_t i = 0; i < 6; ++i) {
+ // Convert the 5-bit groups in mod to checksum values.
+ ret[i] = (mod >> (5 * (5 - i))) & 31;
+ }
+ return ret;
+}
+
+} // namespace
+
+namespace bech32
+{
+
+/** Encode a Bech32 string. */
+std::string Encode(const std::string& hrp, const data& values) {
+ data checksum = CreateChecksum(hrp, values);
+ data combined = Cat(values, checksum);
+ std::string ret = hrp + '1';
+ ret.reserve(ret.size() + combined.size());
+ for (auto c : combined) {
+ ret += CHARSET[c];
+ }
+ return ret;
+}
+
+/** Decode a Bech32 string. */
+std::pair<std::string, data> Decode(const std::string& str) {
+ bool lower = false, upper = false;
+ for (size_t i = 0; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ if (c < 33 || c > 126) return {};
+ if (c >= 'a' && c <= 'z') lower = true;
+ if (c >= 'A' && c <= 'Z') upper = true;
+ }
+ if (lower && upper) return {};
+ size_t pos = str.rfind('1');
+ if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
+ return {};
+ }
+ data values(str.size() - 1 - pos);
+ for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
+ unsigned char c = str[i + pos + 1];
+ int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
+ if (rev == -1) {
+ return {};
+ }
+ values[i] = rev;
+ }
+ std::string hrp;
+ for (size_t i = 0; i < pos; ++i) {
+ hrp += LowerCase(str[i]);
+ }
+ if (!VerifyChecksum(hrp, values)) {
+ return {};
+ }
+ return {hrp, data(values.begin(), values.end() - 6)};
+}
+
+} // namespace bech32
diff --git a/src/bech32.h b/src/bech32.h
new file mode 100644
index 0000000000..7ef7b22213
--- /dev/null
+++ b/src/bech32.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// Bech32 is a string encoding format used in newer address types.
+// The output consists of a human-readable part (alphanumeric), a
+// separator character (1), and a base32 data section, the last
+// 6 characters of which are a checksum.
+//
+// For more information, see BIP 173.
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace bech32
+{
+
+/** Encode a Bech32 string. Returns the empty string in case of failure. */
+std::string Encode(const std::string& hrp, const std::vector<uint8_t>& values);
+
+/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
+std::pair<std::string, std::vector<uint8_t>> Decode(const std::string& str);
+
+} // namespace bech32
diff --git a/src/bench/Examples.cpp b/src/bench/Examples.cpp
index 314947d48c..536e450940 100644
--- a/src/bench/Examples.cpp
+++ b/src/bench/Examples.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "validation.h"
-#include "utiltime.h"
+#include <bench/bench.h>
+#include <validation.h>
+#include <utiltime.h>
// Sanity test: this should loop ten times, and
// min/max/average should be close to 100ms.
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 65e27a615d..2d9a9f2908 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "validation.h"
-#include "base58.h"
+#include <validation.h>
+#include <base58.h>
#include <array>
#include <vector>
@@ -22,7 +22,7 @@ static void Base58Encode(benchmark::State& state)
}
};
while (state.KeepRunning()) {
- EncodeBase58(buff.begin(), buff.end());
+ EncodeBase58(buff.data(), buff.data() + buff.size());
}
}
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 849d924af2..1482452814 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -2,35 +2,31 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "perf.h"
+#include <bench/bench.h>
+#include <bench/perf.h>
#include <assert.h>
#include <iostream>
#include <iomanip>
-#include <sys/time.h>
benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
return benchmarks_map;
}
-static double gettimedouble(void) {
- struct timeval tv;
- gettimeofday(&tv, nullptr);
- return tv.tv_usec * 0.000001 + tv.tv_sec;
-}
-
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
benchmarks().insert(std::make_pair(name, func));
}
void
-benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
+benchmark::BenchRunner::RunAll(benchmark::duration elapsedTimeForOne)
{
perf_init();
- std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
+ if (std::ratio_less_equal<benchmark::clock::period, std::micro>::value) {
+ std::cerr << "WARNING: Clock precision is worse than microsecond - benchmarks may be less accurate!\n";
+ }
+ std::cout << "#Benchmark" << "," << "count" << "," << "min(ns)" << "," << "max(ns)" << "," << "average(ns)" << ","
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
for (const auto &p: benchmarks()) {
@@ -46,22 +42,23 @@ bool benchmark::State::KeepRunning()
++count;
return true;
}
- double now;
+ time_point now;
+
uint64_t nowCycles;
if (count == 0) {
- lastTime = beginTime = now = gettimedouble();
+ lastTime = beginTime = now = clock::now();
lastCycles = beginCycles = nowCycles = perf_cpucycles();
}
else {
- now = gettimedouble();
- double elapsed = now - lastTime;
- double elapsedOne = elapsed * countMaskInv;
+ now = clock::now();
+ auto elapsed = now - lastTime;
+ auto elapsedOne = elapsed / (countMask + 1);
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
// We only use relative values, so don't have to handle 64-bit wrap-around specially
nowCycles = perf_cpucycles();
- uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;
+ uint64_t elapsedOneCycles = (nowCycles - lastCycles) / (countMask + 1);
if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
@@ -69,10 +66,9 @@ bool benchmark::State::KeepRunning()
// If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
// The restart avoids including the overhead of this code in the measurement.
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
- countMaskInv = 1./(countMask+1);
count = 0;
- minTime = std::numeric_limits<double>::max();
- maxTime = std::numeric_limits<double>::min();
+ minTime = duration::max();
+ maxTime = duration::zero();
minCycles = std::numeric_limits<uint64_t>::max();
maxCycles = std::numeric_limits<uint64_t>::min();
return true;
@@ -81,7 +77,6 @@ bool benchmark::State::KeepRunning()
uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
if ((count & newCountMask)==0) {
countMask = newCountMask;
- countMaskInv = 1./(countMask+1);
}
}
}
@@ -96,9 +91,13 @@ bool benchmark::State::KeepRunning()
assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
// Output results
- double average = (now-beginTime)/count;
+ // Duration casts are only necessary here because hardware with sub-nanosecond clocks
+ // will lose precision.
+ int64_t min_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(minTime).count();
+ int64_t max_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(maxTime).count();
+ int64_t avg_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>((now-beginTime)/count).count();
int64_t averageCycles = (nowCycles-beginCycles)/count;
- std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << min_elapsed << "," << max_elapsed << "," << avg_elapsed << ","
<< minCycles << "," << maxCycles << "," << averageCycles << "\n";
std::cout.copyfmt(std::ios(nullptr));
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 1f36f2a4bc..071a5dc9c7 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -9,6 +9,7 @@
#include <limits>
#include <map>
#include <string>
+#include <chrono>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
@@ -36,12 +37,21 @@ BENCHMARK(CODE_TO_TIME);
*/
namespace benchmark {
+ // In case high_resolution_clock is steady, prefer that, otherwise use steady_clock.
+ struct best_clock {
+ using hi_res_clock = std::chrono::high_resolution_clock;
+ using steady_clock = std::chrono::steady_clock;
+ using type = std::conditional<hi_res_clock::is_steady, hi_res_clock, steady_clock>::type;
+ };
+ using clock = best_clock::type;
+ using time_point = clock::time_point;
+ using duration = clock::duration;
class State {
std::string name;
- double maxElapsed;
- double beginTime;
- double lastTime, minTime, maxTime, countMaskInv;
+ duration maxElapsed;
+ time_point beginTime, lastTime;
+ duration minTime, maxTime;
uint64_t count;
uint64_t countMask;
uint64_t beginCycles;
@@ -49,13 +59,17 @@ namespace benchmark {
uint64_t minCycles;
uint64_t maxCycles;
public:
- State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
- minTime = std::numeric_limits<double>::max();
- maxTime = std::numeric_limits<double>::min();
- minCycles = std::numeric_limits<uint64_t>::max();
- maxCycles = std::numeric_limits<uint64_t>::min();
- countMask = 1;
- countMaskInv = 1./(countMask + 1);
+ State(std::string _name, duration _maxElapsed) :
+ name(_name),
+ maxElapsed(_maxElapsed),
+ minTime(duration::max()),
+ maxTime(duration::zero()),
+ count(0),
+ countMask(1),
+ beginCycles(0),
+ lastCycles(0),
+ minCycles(std::numeric_limits<uint64_t>::max()),
+ maxCycles(std::numeric_limits<uint64_t>::min()) {
}
bool KeepRunning();
};
@@ -70,7 +84,7 @@ namespace benchmark {
public:
BenchRunner(std::string name, BenchFunction func);
- static void RunAll(double elapsedTimeForOne=1.0);
+ static void RunAll(duration elapsedTimeForOne = std::chrono::seconds(1));
};
}
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 37fd772435..84e51d809a 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "crypto/sha256.h"
-#include "key.h"
-#include "validation.h"
-#include "util.h"
-#include "random.h"
+#include <crypto/sha256.h>
+#include <key.h>
+#include <validation.h>
+#include <util.h>
+#include <random.h>
int
main(int argc, char** argv)
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 5aab3381fd..89ba3d3d21 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "coins.h"
-#include "policy/policy.h"
-#include "wallet/crypter.h"
+#include <bench/bench.h>
+#include <coins.h>
+#include <policy/policy.h>
+#include <wallet/crypter.h>
#include <vector>
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 7bb1b93668..9533b3c711 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -2,15 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "chainparams.h"
-#include "validation.h"
-#include "streams.h"
-#include "consensus/validation.h"
+#include <chainparams.h>
+#include <validation.h>
+#include <streams.h>
+#include <consensus/validation.h>
namespace block_bench {
-#include "bench/data/block413567.raw.h"
+#include <bench/data/block413567.raw.h>
} // namespace block_bench
// These are the two major time-sinks which happen after we have fully received
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 88a2a570f9..35750aa1b6 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "util.h"
-#include "validation.h"
-#include "checkqueue.h"
-#include "prevector.h"
+#include <bench/bench.h>
+#include <util.h>
+#include <validation.h>
+#include <checkqueue.h>
+#include <prevector.h>
#include <vector>
#include <boost/thread/thread.hpp>
-#include "random.h"
+#include <random.h>
// This Benchmark tests the CheckQueue with the lightest
@@ -19,7 +19,7 @@ static const int MIN_CORES = 2;
static const size_t BATCHES = 101;
static const size_t BATCH_SIZE = 30;
static const int PREVECTOR_SIZE = 28;
-static const int QUEUE_BATCH_SIZE = 128;
+static const unsigned int QUEUE_BATCH_SIZE = 128;
static void CCheckQueueSpeed(benchmark::State& state)
{
struct FakeJobNoWork {
@@ -67,7 +67,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::State& state)
prevector<PREVECTOR_SIZE, uint8_t> p;
PrevectorJob(){
}
- PrevectorJob(FastRandomContext& insecure_rand){
+ explicit PrevectorJob(FastRandomContext& insecure_rand){
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
}
bool operator()()
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index f8956508f6..ff57f88170 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "wallet/wallet.h"
+#include <bench/bench.h>
+#include <wallet/wallet.h>
#include <set>
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 2914a36c7b..b37b5cad62 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -4,16 +4,16 @@
#include <iostream>
-#include "bench.h"
-#include "bloom.h"
-#include "hash.h"
-#include "random.h"
-#include "uint256.h"
-#include "utiltime.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/sha512.h"
+#include <bench/bench.h>
+#include <bloom.h>
+#include <hash.h>
+#include <random.h>
+#include <uint256.h>
+#include <utiltime.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <crypto/sha512.h>
/* Number of bytes to hash per iteration */
static const uint64_t BUFFER_SIZE = 1000*1000;
@@ -47,7 +47,7 @@ static void SHA256_32b(benchmark::State& state)
std::vector<uint8_t> in(32,0);
while (state.KeepRunning()) {
for (int i = 0; i < 1000000; i++) {
- CSHA256().Write(in.data(), in.size()).Finalize(&in[0]);
+ CSHA256().Write(in.data(), in.size()).Finalize(in.data());
}
}
}
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index 43a1422795..b0bfa95144 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "support/lockedpool.h"
+#include <support/lockedpool.h>
#include <iostream>
#include <vector>
@@ -21,14 +21,14 @@ static void BenchLockedPool(benchmark::State& state)
std::vector<void*> addr;
for (int x=0; x<ASIZE; ++x)
- addr.push_back(0);
+ addr.push_back(nullptr);
uint32_t s = 0x12345678;
while (state.KeepRunning()) {
for (int x=0; x<BITER; ++x) {
int idx = s & (addr.size()-1);
if (s & 0x80000000) {
b.free(addr[idx]);
- addr[idx] = 0;
+ addr[idx] = nullptr;
} else if(!addr[idx]) {
addr[idx] = b.alloc((s >> 16) & (MSIZE-1));
}
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 073bbde016..eda6edbb23 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "policy/policy.h"
-#include "txmempool.h"
+#include <bench/bench.h>
+#include <policy/policy.h>
+#include <txmempool.h>
#include <list>
#include <vector>
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
index a549ec29ea..4045670a31 100644
--- a/src/bench/perf.cpp
+++ b/src/bench/perf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "perf.h"
+#include <bench/perf.h>
#if defined(__i386__) || defined(__x86_64__)
diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp
index 55af3de4fe..de7ecab737 100644
--- a/src/bench/prevector_destructor.cpp
+++ b/src/bench/prevector_destructor.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "prevector.h"
+#include <bench/bench.h>
+#include <prevector.h>
static void PrevectorDestructor(benchmark::State& state)
{
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 73c02cf718..452099b800 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -4,9 +4,8 @@
#include <iostream>
-#include "bench.h"
-#include "bloom.h"
-#include "utiltime.h"
+#include <bench/bench.h>
+#include <bloom.h>
static void RollingBloom(benchmark::State& state)
{
@@ -23,10 +22,10 @@ static void RollingBloom(benchmark::State& state)
data[2] = count >> 16;
data[3] = count >> 24;
if (countnow == nEntriesPerGeneration) {
- int64_t b = GetTimeMicros();
+ auto b = benchmark::clock::now();
filter.insert(data);
- int64_t e = GetTimeMicros();
- std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
+ auto total = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark::clock::now() - b).count();
+ std::cout << "RollingBloom-refresh,1," << total << "," << total << "," << total << "\n";
countnow = 0;
} else {
filter.insert(data);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index ef7381c120..bfa5806c9d 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "key.h"
+#include <bench/bench.h>
+#include <key.h>
#if defined(HAVE_CONSENSUS_LIB)
-#include "script/bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
#endif
-#include "script/script.h"
-#include "script/sign.h"
-#include "streams.h"
+#include <script/script.h>
+#include <script/sign.h>
+#include <streams.h>
#include <array>
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 8bec0289f5..136981b709 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -4,22 +4,22 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparamsbase.h"
-#include "clientversion.h"
-#include "fs.h"
-#include "rpc/client.h"
-#include "rpc/protocol.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <chainparamsbase.h>
+#include <clientversion.h>
+#include <fs.h>
+#include <rpc/client.h>
+#include <rpc/protocol.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <stdio.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
-#include "support/events.h"
+#include <support/events.h>
#include <univalue.h>
@@ -37,6 +37,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
+ strUsage += HelpMessageOpt("-getinfo", _("Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)"));
AppendParamsHelpMessages(strUsage);
strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
@@ -45,7 +46,8 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
- strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
+ strUsage += HelpMessageOpt("-stdinrpcpass", strprintf(_("Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.")));
+ strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password."));
strUsage += HelpMessageOpt("-rpcwallet=<walletname>", _("Send RPC for non-default wallet on RPC server (argument is wallet filename in bitcoind directory, required if bitcoind/-Qt runs with multiple wallets)"));
return strUsage;
@@ -190,7 +192,99 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-UniValue CallRPC(const std::string& strMethod, const UniValue& params)
+/** Class that handles the conversion from a command-line to a JSON-RPC request,
+ * as well as converting back to a JSON object that can be shown as result.
+ */
+class BaseRequestHandler
+{
+public:
+ virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
+ virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
+};
+
+/** Process getinfo requests */
+class GetinfoRequestHandler: public BaseRequestHandler
+{
+public:
+ const int ID_NETWORKINFO = 0;
+ const int ID_BLOCKCHAININFO = 1;
+ const int ID_WALLETINFO = 2;
+
+ /** Create a simulated `getinfo` request. */
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ if (!args.empty()) {
+ throw std::runtime_error("-getinfo takes no arguments");
+ }
+ UniValue result(UniValue::VARR);
+ result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
+ result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
+ result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
+ return result;
+ }
+
+ /** Collect values from the batch and form a simulated `getinfo` reply. */
+ UniValue ProcessReply(const UniValue &batch_in) override
+ {
+ UniValue result(UniValue::VOBJ);
+ std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in, 3);
+ // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
+ // getwalletinfo() is allowed to fail in case there is no wallet.
+ if (!batch[ID_NETWORKINFO]["error"].isNull()) {
+ return batch[ID_NETWORKINFO];
+ }
+ if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
+ return batch[ID_BLOCKCHAININFO];
+ }
+ result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
+ result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]);
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ }
+ result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
+ result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
+ result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
+ result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
+ result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
+ result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test"));
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ result.pushKV("keypoololdest", batch[ID_WALLETINFO]["result"]["keypoololdest"]);
+ result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
+ if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
+ result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
+ }
+ result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
+ }
+ result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
+ result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
+ return JSONRPCReplyObj(result, NullUniValue, 1);
+ }
+};
+
+/** Process default single requests */
+class DefaultRequestHandler: public BaseRequestHandler {
+public:
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue params;
+ if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
+ params = RPCConvertNamedValues(method, args);
+ } else {
+ params = RPCConvertValues(method, args);
+ }
+ return JSONRPCRequestObj(method, params, 1);
+ }
+
+ UniValue ProcessReply(const UniValue &reply) override
+ {
+ return reply.get_obj();
+ }
+};
+
+static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
{
std::string host;
// In preference order, we choose the following for the port:
@@ -222,7 +316,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
throw std::runtime_error(strprintf(
- _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
+ _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
}
@@ -237,7 +331,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
+ std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
@@ -276,7 +370,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw std::runtime_error("couldn't parse reply from server");
- const UniValue& reply = valReply.get_obj();
+ const UniValue reply = rh->ProcessReply(valReply);
if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties");
@@ -293,30 +387,40 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
+ std::string rpcPass;
+ if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
+ if (!std::getline(std::cin, rpcPass)) {
+ throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
+ }
+ gArgs.ForceSetArg("-rpcpassword", rpcPass);
+ }
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
if (gArgs.GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
- while (std::getline(std::cin,line))
+ while (std::getline(std::cin, line)) {
args.push_back(line);
+ }
}
- if (args.size() < 1)
- throw std::runtime_error("too few parameters (need at least command)");
- std::string strMethod = args[0];
- args.erase(args.begin()); // Remove trailing method name from arguments vector
-
- UniValue params;
- if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
- params = RPCConvertNamedValues(strMethod, args);
+ std::unique_ptr<BaseRequestHandler> rh;
+ std::string method;
+ if (gArgs.GetBoolArg("-getinfo", false)) {
+ rh.reset(new GetinfoRequestHandler());
+ method = "";
} else {
- params = RPCConvertValues(strMethod, args);
+ rh.reset(new DefaultRequestHandler());
+ if (args.size() < 1) {
+ throw std::runtime_error("too few parameters (need at least command)");
+ }
+ method = args[0];
+ args.erase(args.begin()); // Remove trailing method name from arguments vector
}
// Execute and handle connection failures with -rpcwait
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
do {
try {
- const UniValue reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(rh.get(), method, args);
// Parse reply
const UniValue& result = find_value(reply, "result");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index cff90d13af..c9223dbf10 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -3,24 +3,24 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "base58.h"
-#include "clientversion.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "core_io.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sign.h"
+#include <base58.h>
+#include <clientversion.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <core_io.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <script/sign.h>
#include <univalue.h>
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
#include <stdio.h>
@@ -271,11 +271,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
// extract and validate ADDRESS
std::string strAddr = vStrInputParts[1];
- CBitcoinAddress addr(strAddr);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddr);
+ if (!IsValidDestination(destination)) {
throw std::runtime_error("invalid TX output address");
- // build standard output script via GetScriptForDestination()
- CScript scriptPubKey = GetScriptForDestination(addr.Get());
+ }
+ CScript scriptPubKey = GetScriptForDestination(destination);
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
@@ -310,14 +310,15 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
}
if (bSegWit) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress redeemScriptAddr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -377,14 +378,21 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
if (bSegWit) {
+ for (CPubKey& pubkey : pubkeys) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
+ }
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -443,12 +451,20 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
bScriptHash = (flags.find("S") != std::string::npos);
}
+ if (scriptPubKey.size() > MAX_SCRIPT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE));
+ }
+
if (bSegWit) {
- scriptPubKey = GetScriptForWitness(scriptPubKey);
+ scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
+ }
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -687,10 +703,10 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
else if (command == "outpubkey") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxAddOutPubKey(tx, commandVal);
} else if (command == "outmultisig") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxAddOutMultiSig(tx, commandVal);
} else if (command == "outscript")
MutateTxAddOutScript(tx, commandVal);
@@ -698,7 +714,7 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxAddOutData(tx, commandVal);
else if (command == "sign") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxSign(tx, commandVal);
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 543eba0e69..bc23912d2b 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -4,21 +4,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparams.h"
-#include "clientversion.h"
-#include "compat.h"
-#include "fs.h"
-#include "rpc/server.h"
-#include "init.h"
-#include "noui.h"
-#include "scheduler.h"
-#include "util.h"
-#include "httpserver.h"
-#include "httprpc.h"
-#include "utilstrencodings.h"
+#include <chainparams.h>
+#include <clientversion.h>
+#include <compat.h>
+#include <fs.h>
+#include <rpc/server.h>
+#include <init.h>
+#include <noui.h>
+#include <scheduler.h>
+#include <util.h>
+#include <httpserver.h>
+#include <httprpc.h>
+#include <utilstrencodings.h>
#include <boost/thread.hpp>
@@ -120,7 +120,7 @@ bool AppInit(int argc, char* argv[])
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
- exit(EXIT_FAILURE);
+ return false;
}
}
@@ -132,17 +132,17 @@ bool AppInit(int argc, char* argv[])
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (gArgs.GetBoolArg("-daemon", false))
{
@@ -163,7 +163,7 @@ bool AppInit(int argc, char* argv[])
if (!AppInitLockDataDirectory())
{
// If locking the data directory failed, exit immediately
- exit(EXIT_FAILURE);
+ return false;
}
fRet = AppInitMain(threadGroup, scheduler);
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 6f27b7b9dc..6ff4d97bf4 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "blockencodings.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "chainparams.h"
-#include "hash.h"
-#include "random.h"
-#include "streams.h"
-#include "txmempool.h"
-#include "validation.h"
-#include "util.h"
+#include <blockencodings.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <chainparams.h>
+#include <hash.h>
+#include <random.h>
+#include <streams.h>
+#include <txmempool.h>
+#include <validation.h>
+#include <util.h>
#include <unordered_map>
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 5a1d80d421..d034bb3080 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_BLOCK_ENCODINGS_H
#define BITCOIN_BLOCK_ENCODINGS_H
-#include "primitives/block.h"
+#include <primitives/block.h>
#include <memory>
@@ -16,7 +16,7 @@ struct TransactionCompressor {
private:
CTransactionRef& tx;
public:
- TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
+ explicit TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
ADD_SERIALIZE_METHODS;
@@ -75,7 +75,7 @@ public:
std::vector<CTransactionRef> txn;
BlockTransactions() {}
- BlockTransactions(const BlockTransactionsRequest& req) :
+ explicit BlockTransactions(const BlockTransactionsRequest& req) :
blockhash(req.blockhash), txn(req.indexes.size()) {}
ADD_SERIALIZE_METHODS;
@@ -198,7 +198,7 @@ protected:
CTxMemPool* pool;
public:
CBlockHeader header;
- PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
+ explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
diff --git a/src/bloom.cpp b/src/bloom.cpp
index fa884f0bf3..11ea099637 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bloom.h"
-
-#include "primitives/transaction.h"
-#include "hash.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "random.h"
-#include "streams.h"
+#include <bloom.h>
+
+#include <primitives/transaction.h>
+#include <hash.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <random.h>
+#include <streams.h>
#include <math.h>
#include <stdlib.h>
diff --git a/src/bloom.h b/src/bloom.h
index 7ca9682239..d29a8dcd6f 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_BLOOM_H
#define BITCOIN_BLOOM_H
-#include "serialize.h"
+#include <serialize.h>
#include <vector>
diff --git a/src/chain.cpp b/src/chain.cpp
index 47acde882e..7ebc08a50b 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
+#include <chain.h>
/**
* CChain implementation
@@ -80,12 +80,13 @@ int static inline GetSkipHeight(int height) {
return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);
}
-CBlockIndex* CBlockIndex::GetAncestor(int height)
+const CBlockIndex* CBlockIndex::GetAncestor(int height) const
{
- if (height > nHeight || height < 0)
+ if (height > nHeight || height < 0) {
return nullptr;
+ }
- CBlockIndex* pindexWalk = this;
+ const CBlockIndex* pindexWalk = this;
int heightWalk = nHeight;
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
@@ -106,9 +107,9 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
return pindexWalk;
}
-const CBlockIndex* CBlockIndex::GetAncestor(int height) const
+CBlockIndex* CBlockIndex::GetAncestor(int height)
{
- return const_cast<CBlockIndex*>(this)->GetAncestor(height);
+ return const_cast<CBlockIndex*>(static_cast<const CBlockIndex*>(this)->GetAncestor(height));
}
void CBlockIndex::BuildSkip()
@@ -128,7 +129,7 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
// as it's too large for an arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
- // or ~bnTarget / (nTarget+1) + 1.
+ // or ~bnTarget / (bnTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
}
diff --git a/src/chain.h b/src/chain.h
index 1223539e73..ca1900c22b 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_CHAIN_H
#define BITCOIN_CHAIN_H
-#include "arith_uint256.h"
-#include "primitives/block.h"
-#include "pow.h"
-#include "tinyformat.h"
-#include "uint256.h"
+#include <arith_uint256.h>
+#include <primitives/block.h>
+#include <pow.h>
+#include <tinyformat.h>
+#include <uint256.h>
#include <vector>
@@ -204,19 +204,19 @@ public:
unsigned int nChainTx;
//! Verification status of this block. See enum BlockStatus
- unsigned int nStatus;
+ uint32_t nStatus;
//! block header
- int nVersion;
+ int32_t nVersion;
uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
+ uint32_t nTime;
+ uint32_t nBits;
+ uint32_t nNonce;
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
int32_t nSequenceId;
- //! (memory only) Maximum nTime in the chain upto and including this block.
+ //! (memory only) Maximum nTime in the chain up to and including this block.
unsigned int nTimeMax;
void SetNull()
@@ -247,7 +247,7 @@ public:
SetNull();
}
- CBlockIndex(const CBlockHeader& block)
+ explicit CBlockIndex(const CBlockHeader& block)
{
SetNull();
@@ -304,7 +304,7 @@ public:
return (int64_t)nTimeMax;
}
- enum { nMedianTimeSpan=11 };
+ static constexpr int nMedianTimeSpan = 11;
int64_t GetMedianTimePast() const
{
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 2021ec51db..e75d3be4c1 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "consensus/merkle.h"
+#include <chainparams.h>
+#include <consensus/merkle.h>
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <assert.h>
-#include "chainparamsseeds.h"
+#include <chainparamsseeds.h>
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
@@ -75,6 +75,7 @@ public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP16Height = 173805; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - April 1, 2012
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
@@ -137,13 +138,15 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
+ bech32_hrp = "bc";
+
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{ 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
{ 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
@@ -179,6 +182,7 @@ public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP16Height = 514; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@@ -228,7 +232,6 @@ public:
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
vSeeds.emplace_back("testnet-seed.bluematt.me", false);
- vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -236,6 +239,8 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+ bech32_hrp = "tb";
+
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
fDefaultConsistencyChecks = false;
@@ -243,7 +248,7 @@ public:
fMineBlocksOnDemand = false;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
}
@@ -267,6 +272,7 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
+ consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
@@ -280,13 +286,13 @@ public:
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
@@ -313,7 +319,7 @@ public:
fRequireStandard = false;
fMineBlocksOnDemand = true;
- checkpointData = (CCheckpointData) {
+ checkpointData = {
{
{0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
}
@@ -330,6 +336,8 @@ public:
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "bcrt";
}
};
diff --git a/src/chainparams.h b/src/chainparams.h
index f55ae4cf7f..0d82a998b1 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_CHAINPARAMS_H
#define BITCOIN_CHAINPARAMS_H
-#include "chainparamsbase.h"
-#include "consensus/params.h"
-#include "primitives/block.h"
-#include "protocol.h"
+#include <chainparamsbase.h>
+#include <consensus/params.h>
+#include <primitives/block.h>
+#include <protocol.h>
#include <memory>
#include <vector>
@@ -73,6 +73,7 @@ public:
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
+ const std::string& Bech32HRP() const { return bech32_hrp; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
const ChainTxData& TxData() const { return chainTxData; }
@@ -86,6 +87,7 @@ protected:
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
+ std::string bech32_hrp;
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 224c9eb0ea..a7e87faee3 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparamsbase.h"
+#include <chainparamsbase.h>
-#include "tinyformat.h"
-#include "util.h"
+#include <tinyformat.h>
+#include <util.h>
#include <assert.h>
@@ -57,7 +57,7 @@ class CBaseRegTestParams : public CBaseChainParams
public:
CBaseRegTestParams()
{
- nRPCPort = 18332;
+ nRPCPort = 18443;
strDataDir = "regtest";
}
};
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 5afe3e66b6..929d864588 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -2,13 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "checkpoints.h"
+#include <checkpoints.h>
-#include "chain.h"
-#include "chainparams.h"
-#include "reverse_iterator.h"
-#include "validation.h"
-#include "uint256.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <reverse_iterator.h>
+#include <validation.h>
#include <stdint.h>
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 7449d1063b..df97a674a8 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CHECKPOINTS_H
#define BITCOIN_CHECKPOINTS_H
-#include "uint256.h"
+#include <uint256.h>
#include <map>
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 4bc6be45f8..08de336079 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CHECKQUEUE_H
#define BITCOIN_CHECKQUEUE_H
-#include "sync.h"
+#include <sync.h>
#include <algorithm>
#include <vector>
@@ -131,7 +131,7 @@ public:
boost::mutex ControlMutex;
//! Create a new check queue
- CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
+ explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
//! Worker thread
void Thread()
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index d2344ded09..1934e71bbc 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -2,15 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "clientversion.h"
+#include <clientversion.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
-#include <string>
/**
* Name of client reported in the 'version' message. Report the same name
- * for both bitcoind and bitcoin-core, to make it harder for attackers to
+ * for both bitcoind and bitcoin-qt, to make it harder for attackers to
* target servers or GUI users specifically.
*/
const std::string CLIENT_NAME("Satoshi");
@@ -39,7 +38,7 @@ const std::string CLIENT_NAME("Satoshi");
//! First, include build.h if requested
#ifdef HAVE_BUILD_INFO
-#include "build.h"
+#include <obj/build.h>
#endif
//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
diff --git a/src/clientversion.h b/src/clientversion.h
index 3d5392619b..3a3d117d53 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -6,7 +6,7 @@
#define BITCOIN_CLIENTVERSION_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif //HAVE_CONFIG_H
// Check that required client information is defined
diff --git a/src/coins.cpp b/src/coins.cpp
index e30bda930a..afaf5ccc13 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -2,19 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coins.h"
+#include <coins.h>
-#include "consensus/consensus.h"
-#include "memusage.h"
-#include "random.h"
-
-#include <assert.h>
+#include <consensus/consensus.h>
+#include <random.h>
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
-CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
+CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
{
@@ -146,56 +143,58 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
- for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
- CCoinsMap::iterator itUs = cacheCoins.find(it->first);
- if (itUs == cacheCoins.end()) {
- // The parent cache does not have an entry, while the child does
- // We can ignore it if it's both FRESH and pruned in the child
- if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
- // Otherwise we will need to create it in the parent
- // and move the data up and mark it as dirty
- CCoinsCacheEntry& entry = cacheCoins[it->first];
- entry.coin = std::move(it->second.coin);
- cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
- entry.flags = CCoinsCacheEntry::DIRTY;
- // We can mark it FRESH in the parent if it was FRESH in the child
- // Otherwise it might have just been flushed from the parent's cache
- // and already exist in the grandparent
- if (it->second.flags & CCoinsCacheEntry::FRESH)
- entry.flags |= CCoinsCacheEntry::FRESH;
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
+ // Ignore non-dirty entries (optimization).
+ if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
+ continue;
+ }
+ CCoinsMap::iterator itUs = cacheCoins.find(it->first);
+ if (itUs == cacheCoins.end()) {
+ // The parent cache does not have an entry, while the child does
+ // We can ignore it if it's both FRESH and pruned in the child
+ if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
+ // Otherwise we will need to create it in the parent
+ // and move the data up and mark it as dirty
+ CCoinsCacheEntry& entry = cacheCoins[it->first];
+ entry.coin = std::move(it->second.coin);
+ cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
+ entry.flags = CCoinsCacheEntry::DIRTY;
+ // We can mark it FRESH in the parent if it was FRESH in the child
+ // Otherwise it might have just been flushed from the parent's cache
+ // and already exist in the grandparent
+ if (it->second.flags & CCoinsCacheEntry::FRESH) {
+ entry.flags |= CCoinsCacheEntry::FRESH;
}
- } else {
- // Assert that the child cache entry was not marked FRESH if the
- // parent cache entry has unspent outputs. If this ever happens,
- // it means the FRESH flag was misapplied and there is a logic
- // error in the calling code.
- if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
- throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
+ }
+ } else {
+ // Assert that the child cache entry was not marked FRESH if the
+ // parent cache entry has unspent outputs. If this ever happens,
+ // it means the FRESH flag was misapplied and there is a logic
+ // error in the calling code.
+ if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
+ throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
+ }
- // Found the entry in the parent cache
- if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
- // The grandparent does not have an entry, and the child is
- // modified and being pruned. This means we can just delete
- // it from the parent.
- cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
- cacheCoins.erase(itUs);
- } else {
- // A normal modification.
- cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
- itUs->second.coin = std::move(it->second.coin);
- cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
- itUs->second.flags |= CCoinsCacheEntry::DIRTY;
- // NOTE: It is possible the child has a FRESH flag here in
- // the event the entry we found in the parent is pruned. But
- // we must not copy that FRESH flag to the parent as that
- // pruned state likely still needs to be communicated to the
- // grandparent.
- }
+ // Found the entry in the parent cache
+ if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
+ // The grandparent does not have an entry, and the child is
+ // modified and being pruned. This means we can just delete
+ // it from the parent.
+ cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
+ cacheCoins.erase(itUs);
+ } else {
+ // A normal modification.
+ cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
+ itUs->second.coin = std::move(it->second.coin);
+ cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
+ itUs->second.flags |= CCoinsCacheEntry::DIRTY;
+ // NOTE: It is possible the child has a FRESH flag here in
+ // the event the entry we found in the parent is pruned. But
+ // we must not copy that FRESH flag to the parent as that
+ // pruned state likely still needs to be communicated to the
+ // grandparent.
}
}
- CCoinsMap::iterator itOld = it++;
- mapCoins.erase(itOld);
}
hashBlock = hashBlockIn;
return true;
diff --git a/src/coins.h b/src/coins.h
index efb5ce869c..0280abb56c 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,13 +6,13 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
-#include "primitives/transaction.h"
-#include "compressor.h"
-#include "core_memusage.h"
-#include "hash.h"
-#include "memusage.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <compressor.h>
+#include <core_memusage.h>
+#include <hash.h>
+#include <memusage.h>
+#include <serialize.h>
+#include <uint256.h>
#include <assert.h>
#include <stdint.h>
@@ -214,6 +214,11 @@ protected:
public:
CCoinsViewCache(CCoinsView *baseIn);
+ /**
+ * By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
+ */
+ CCoinsViewCache(const CCoinsViewCache &) = delete;
+
// Standard CCoinsView methods
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
@@ -290,11 +295,6 @@ public:
private:
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
-
- /**
- * By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.
- */
- CCoinsViewCache(const CCoinsViewCache &);
};
//! Utility function to add all of a transaction's outputs to a cache.
diff --git a/src/compat.h b/src/compat.h
index e022659c01..89cc4709a4 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -7,7 +7,7 @@
#define BITCOIN_COMPAT_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#ifdef WIN32
@@ -31,6 +31,7 @@
#include <mswsock.h>
#include <windows.h>
#include <ws2tcpip.h>
+#include <stdint.h>
#else
#include <sys/fcntl.h>
#include <sys/mman.h>
@@ -49,7 +50,7 @@
#ifndef WIN32
typedef unsigned int SOCKET;
-#include "errno.h"
+#include <errno.h>
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
#define WSAEALREADY EALREADY
@@ -71,6 +72,15 @@ typedef unsigned int SOCKET;
#else
#define MAX_PATH 1024
#endif
+#ifdef _MSC_VER
+#if !defined(ssize_t)
+#ifdef _WIN64
+typedef int64_t ssize_t;
+#else
+typedef int32_t ssize_t;
+#endif
+#endif
+#endif
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 3c5a5c0837..a6df6ded7a 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -6,7 +6,7 @@
#define BITCOIN_COMPAT_BYTESWAP_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdint.h>
@@ -35,9 +35,9 @@
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
{
- return (x >> 8) | ((x & 0x00ff) << 8);
+ return (x >> 8) | (x << 8);
}
-#endif // HAVE_DECL_BSWAP16
+#endif // HAVE_DECL_BSWAP16 == 0
#if HAVE_DECL_BSWAP_32 == 0
inline uint32_t bswap_32(uint32_t x)
@@ -45,7 +45,7 @@ inline uint32_t bswap_32(uint32_t x)
return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) |
((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24));
}
-#endif // HAVE_DECL_BSWAP32
+#endif // HAVE_DECL_BSWAP32 == 0
#if HAVE_DECL_BSWAP_64 == 0
inline uint64_t bswap_64(uint64_t x)
@@ -59,7 +59,7 @@ inline uint64_t bswap_64(uint64_t x)
| ((x & 0x000000000000ff00ull) << 40)
| ((x & 0x00000000000000ffull) << 56));
}
-#endif // HAVE_DECL_BSWAP64
+#endif // HAVE_DECL_BSWAP64 == 0
#endif // defined(__APPLE__)
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 79d6b2fdbb..9fabbd0bfb 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -6,12 +6,12 @@
#define BITCOIN_COMPAT_ENDIAN_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include <stdint.h>
+#include <compat/byteswap.h>
-#include "compat/byteswap.h"
+#include <stdint.h>
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index 3b9c70df7f..6633658c16 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstddef>
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index b4d1c90992..20d2ad3cb6 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstddef>
diff --git a/src/compat/strnlen.cpp b/src/compat/strnlen.cpp
index 1ac266c2d1..313435a222 100644
--- a/src/compat/strnlen.cpp
+++ b/src/compat/strnlen.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstring>
diff --git a/src/compressor.cpp b/src/compressor.cpp
index f4c12f38d2..a729e28f07 100644
--- a/src/compressor.cpp
+++ b/src/compressor.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compressor.h"
+#include <compressor.h>
-#include "hash.h"
-#include "pubkey.h"
-#include "script/standard.h"
+#include <hash.h>
+#include <pubkey.h>
+#include <script/standard.h>
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
{
diff --git a/src/compressor.h b/src/compressor.h
index 015911484a..8731eef9f7 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_COMPRESSOR_H
#define BITCOIN_COMPRESSOR_H
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "serialize.h"
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <serialize.h>
class CKeyID;
class CPubKey;
@@ -53,7 +53,7 @@ protected:
unsigned int GetSpecialSize(unsigned int nSize) const;
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
public:
- CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
+ explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -99,7 +99,7 @@ public:
static uint64_t CompressAmount(uint64_t nAmount);
static uint64_t DecompressAmount(uint64_t nAmount);
- CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+ explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
ADD_SERIALIZE_METHODS;
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index ddd4ee9fab..6e3bac2d0e 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -24,12 +24,9 @@ static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is
static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
/** Flags for nSequence and nLockTime locks */
-enum {
- /* Interpret sequence numbers as relative lock-time constraints. */
- LOCKTIME_VERIFY_SEQUENCE = (1 << 0),
-
- /* Use GetMedianTimePast() instead of nTime for end point timestamp. */
- LOCKTIME_MEDIAN_TIME_PAST = (1 << 1),
-};
+/** Interpret sequence numbers as relative lock-time constraints. */
+static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
+/** Use GetMedianTimePast() instead of nTime for end point timestamp. */
+static constexpr unsigned int LOCKTIME_MEDIAN_TIME_PAST = (1 << 1);
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 798ce4b5fd..fef4a5d560 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "merkle.h"
-#include "hash.h"
-#include "utilstrencodings.h"
+#include <consensus/merkle.h>
+#include <hash.h>
+#include <utilstrencodings.h>
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h
index 33764c7460..c1573cc214 100644
--- a/src/consensus/merkle.h
+++ b/src/consensus/merkle.h
@@ -8,9 +8,9 @@
#include <stdint.h>
#include <vector>
-#include "primitives/transaction.h"
-#include "primitives/block.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <primitives/block.h>
+#include <uint256.h>
uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = nullptr);
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 6240e82857..c9fbba12a2 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -6,7 +6,8 @@
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H
-#include "uint256.h"
+#include <uint256.h>
+#include <limits>
#include <map>
#include <string>
@@ -31,6 +32,15 @@ struct BIP9Deployment {
int64_t nStartTime;
/** Timeout/expiry MedianTime for the deployment attempt. */
int64_t nTimeout;
+
+ /** Constant for nTimeout very far in the future. */
+ static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
+
+ /** Special value for nStartTime indicating that the deployment is always active.
+ * This is useful for testing, as it means tests don't need to deal with the activation
+ * process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
+ * behaviour during activation cannot use this. */
+ static constexpr int64_t ALWAYS_ACTIVE = -1;
};
/**
@@ -39,6 +49,8 @@ struct BIP9Deployment {
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
+ /** Block height at which BIP16 becomes active */
+ int BIP16Height;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 0a71915d1d..be73d0a2f9 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "tx_verify.h"
+#include <consensus/tx_verify.h>
-#include "consensus.h"
-#include "primitives/transaction.h"
-#include "script/interpreter.h"
-#include "validation.h"
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <script/interpreter.h>
+#include <consensus/validation.h>
// TODO remove the following dependencies
-#include "chain.h"
-#include "coins.h"
-#include "utilmoneystr.h"
-
+#include <chain.h>
+#include <coins.h>
+#include <utilmoneystr.h>
+
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
if (tx.nLockTime == 0)
@@ -205,46 +205,46 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
return true;
}
-bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
+bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
{
- // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
- // for an attacker to attempt to split the network.
- if (!inputs.HaveInputs(tx))
- return state.Invalid(false, 0, "", "Inputs unavailable");
-
- CAmount nValueIn = 0;
- CAmount nFees = 0;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const COutPoint &prevout = tx.vin[i].prevout;
- const Coin& coin = inputs.AccessCoin(prevout);
- assert(!coin.IsSpent());
-
- // If prev is coinbase, check that it's matured
- if (coin.IsCoinBase()) {
- if (nSpendHeight - coin.nHeight < COINBASE_MATURITY)
- return state.Invalid(false,
- REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
- strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
- }
-
- // Check for negative or overflow input values
- nValueIn += coin.out.nValue;
- if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
+ // are the actual inputs available?
+ if (!inputs.HaveInputs(tx)) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
+ strprintf("%s: inputs missing/spent", __func__));
+ }
+
+ CAmount nValueIn = 0;
+ for (unsigned int i = 0; i < tx.vin.size(); ++i) {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ const Coin& coin = inputs.AccessCoin(prevout);
+ assert(!coin.IsSpent());
+
+ // If prev is coinbase, check that it's matured
+ if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
+ return state.Invalid(false,
+ REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
+ strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
+ }
+ // Check for negative or overflow input values
+ nValueIn += coin.out.nValue;
+ if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
+ }
+
+ const CAmount value_out = tx.GetValueOut();
+ if (nValueIn < value_out) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
+ strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
+ }
+
+ // Tally transaction fees
+ const CAmount txfee_aux = nValueIn - value_out;
+ if (!MoneyRange(txfee_aux)) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
+ }
- if (nValueIn < tx.GetValueOut())
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
- strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())));
-
- // Tally transaction fees
- CAmount nTxFee = nValueIn - tx.GetValueOut();
- if (nTxFee < 0)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative");
- nFees += nTxFee;
- if (!MoneyRange(nFees))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
+ txfee = txfee_aux;
return true;
}
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index d46d3294ca..a4836ceda4 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H
#define BITCOIN_CONSENSUS_TX_VERIFY_H
+#include <amount.h>
+
#include <stdint.h>
#include <vector>
@@ -22,9 +24,10 @@ namespace Consensus {
/**
* Check whether all inputs of this transaction are valid (no double spends and amounts)
* This does not modify the UTXO set. This does not check scripts and sigs.
+ * @param[out] txfee Set to the transaction fee if successful.
* Preconditions: tx.IsCoinBase() is false.
*/
-bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
} // namespace Consensus
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 5494ce40ea..55f6c363fc 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -7,10 +7,10 @@
#define BITCOIN_CONSENSUS_VALIDATION_H
#include <string>
-#include "version.h"
-#include "consensus/consensus.h"
-#include "primitives/transaction.h"
-#include "primitives/block.h"
+#include <version.h>
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <primitives/block.h>
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
@@ -89,17 +89,16 @@ public:
std::string GetDebugMessage() const { return strDebugMessage; }
};
+// These implement the weight = (stripped_size * 4) + witness_size formula,
+// using only serialization with and without witness data. As witness_size
+// is equal to total_size - stripped_size, this formula is identical to:
+// weight = (stripped_size * 3) + total_size.
static inline int64_t GetTransactionWeight(const CTransaction& tx)
{
- return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+ return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
}
-
static inline int64_t GetBlockWeight(const CBlock& block)
{
- // This implements the weight = (stripped_size * 4) + witness_size formula,
- // using only serialization with and without witness data. As witness_size
- // is equal to total_size - stripped_size, this formula is identical to:
- // weight = (stripped_size * 3) + total_size.
return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
}
diff --git a/src/core_io.h b/src/core_io.h
index 3f25faf0ec..7ed84d6665 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CORE_IO_H
#define BITCOIN_CORE_IO_H
-#include "amount.h"
+#include <amount.h>
#include <string>
#include <vector>
@@ -31,6 +31,6 @@ UniValue ValueFromAmount(const CAmount& amount);
std::string FormatScript(const CScript& script);
std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_memusage.h b/src/core_memusage.h
index f038e7b154..d234f0a9d0 100644
--- a/src/core_memusage.h
+++ b/src/core_memusage.h
@@ -5,9 +5,9 @@
#ifndef BITCOIN_CORE_MEMUSAGE_H
#define BITCOIN_CORE_MEMUSAGE_H
-#include "primitives/transaction.h"
-#include "primitives/block.h"
-#include "memusage.h"
+#include <primitives/transaction.h>
+#include <primitives/block.h>
+#include <memusage.h>
static inline size_t RecursiveDynamicUsage(const CScript& script) {
return memusage::DynamicUsage(script);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 7018131a13..2f5b67b5c7 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core_io.h"
+#include <core_io.h>
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "streams.h"
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <streams.h>
#include <univalue.h>
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 0eae4703ab..e97876bef3 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core_io.h"
-
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "serialize.h"
-#include "streams.h"
+#include <core_io.h>
+
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <serialize.h>
+#include <streams.h>
#include <univalue.h>
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
UniValue ValueFromAmount(const CAmount& amount)
{
@@ -148,12 +148,13 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("type", GetTxnOutputType(type));
UniValue a(UniValue::VARR);
- for (const CTxDestination& addr : addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
out.pushKV("addresses", a);
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -207,5 +208,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
if (!hashBlock.IsNull())
entry.pushKV("blockhash", hashBlock.GetHex());
- entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ if (include_hex) {
+ entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ }
}
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 5e70d25eee..baba8bcad0 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "aes.h"
-#include "crypto/common.h"
+#include <crypto/aes.h>
+#include <crypto/common.h>
#include <assert.h>
#include <string.h>
extern "C" {
-#include "crypto/ctaes/ctaes.c"
+#include <crypto/ctaes/ctaes.c>
}
AES128Encrypt::AES128Encrypt(const unsigned char key[16])
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index e9f1b52e71..7dda94d291 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -8,7 +8,7 @@
#define BITCOIN_CRYPTO_AES_H
extern "C" {
-#include "crypto/ctaes/ctaes.h"
+#include <crypto/ctaes/ctaes.h>
}
static const int AES_BLOCKSIZE = 16;
@@ -22,7 +22,7 @@ private:
AES128_ctx ctx;
public:
- AES128Encrypt(const unsigned char key[16]);
+ explicit AES128Encrypt(const unsigned char key[16]);
~AES128Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -34,7 +34,7 @@ private:
AES128_ctx ctx;
public:
- AES128Decrypt(const unsigned char key[16]);
+ explicit AES128Decrypt(const unsigned char key[16]);
~AES128Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
@@ -46,7 +46,7 @@ private:
AES256_ctx ctx;
public:
- AES256Encrypt(const unsigned char key[32]);
+ explicit AES256Encrypt(const unsigned char key[32]);
~AES256Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -58,7 +58,7 @@ private:
AES256_ctx ctx;
public:
- AES256Decrypt(const unsigned char key[32]);
+ explicit AES256Decrypt(const unsigned char key[32]);
~AES256Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index 4038ae9f86..ac4470f04f 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -5,8 +5,8 @@
// Based on the public domain implementation 'merged' by D. J. Bernstein
// See https://cr.yp.to/chacha.html.
-#include "crypto/common.h"
-#include "crypto/chacha20.h"
+#include <crypto/common.h>
+#include <crypto/chacha20.h>
#include <string.h>
diff --git a/src/crypto/common.h b/src/crypto/common.h
index bcca3d30ea..5a193a4e64 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -6,13 +6,13 @@
#define BITCOIN_CRYPTO_COMMON_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdint.h>
#include <string.h>
-#include "compat/endian.h"
+#include <compat/endian.h>
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
diff --git a/src/crypto/hmac_sha256.cpp b/src/crypto/hmac_sha256.cpp
index 3c791625d0..9366e216c2 100644
--- a/src/crypto/hmac_sha256.cpp
+++ b/src/crypto/hmac_sha256.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/hmac_sha256.h"
+#include <crypto/hmac_sha256.h>
#include <string.h>
diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h
index 1519c1457e..40d40f9fb2 100644
--- a/src/crypto/hmac_sha256.h
+++ b/src/crypto/hmac_sha256.h
@@ -5,12 +5,12 @@
#ifndef BITCOIN_CRYPTO_HMAC_SHA256_H
#define BITCOIN_CRYPTO_HMAC_SHA256_H
-#include "crypto/sha256.h"
+#include <crypto/sha256.h>
#include <stdint.h>
#include <stdlib.h>
-/** A hasher class for HMAC-SHA-512. */
+/** A hasher class for HMAC-SHA-256. */
class CHMAC_SHA256
{
private:
diff --git a/src/crypto/hmac_sha512.cpp b/src/crypto/hmac_sha512.cpp
index 5939c6ec47..f984201f6a 100644
--- a/src/crypto/hmac_sha512.cpp
+++ b/src/crypto/hmac_sha512.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/hmac_sha512.h"
+#include <crypto/hmac_sha512.h>
#include <string.h>
diff --git a/src/crypto/hmac_sha512.h b/src/crypto/hmac_sha512.h
index 17dee61ea8..6d3fd59f27 100644
--- a/src/crypto/hmac_sha512.h
+++ b/src/crypto/hmac_sha512.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CRYPTO_HMAC_SHA512_H
#define BITCOIN_CRYPTO_HMAC_SHA512_H
-#include "crypto/sha512.h"
+#include <crypto/sha512.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp
index 77c9acfc26..4afa9abd1e 100644
--- a/src/crypto/ripemd160.cpp
+++ b/src/crypto/ripemd160.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/ripemd160.h"
+#include <crypto/ripemd160.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp
index 0b895b33a2..8ccc5e112a 100644
--- a/src/crypto/sha1.cpp
+++ b/src/crypto/sha1.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha1.h"
+#include <crypto/sha1.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 15d6db90c2..9a21aec20e 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -2,15 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha256.h"
-#include "crypto/common.h"
+#include <crypto/sha256.h>
+#include <crypto/common.h>
#include <assert.h>
#include <string.h>
#include <atomic>
#if defined(__x86_64__) || defined(__amd64__)
-#if defined(EXPERIMENTAL_ASM)
+#if defined(USE_ASM)
#include <cpuid.h>
namespace sha256_sse4
{
@@ -178,7 +178,7 @@ TransformType Transform = sha256::Transform;
std::string SHA256AutoDetect()
{
-#if defined(EXPERIMENTAL_ASM) && (defined(__x86_64__) || defined(__amd64__))
+#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__))
uint32_t eax, ebx, ecx, edx;
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx >> 19) & 1) {
Transform = sha256_sse4::Transform;
diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp
index 564127cc31..aa46e7ba86 100644
--- a/src/crypto/sha512.cpp
+++ b/src/crypto/sha512.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha512.h"
+#include <crypto/sha512.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index fd24d05ee7..947e1a7185 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_CUCKOOCACHE_H_
-#define _BITCOIN_CUCKOOCACHE_H_
+#ifndef BITCOIN_CUCKOOCACHE_H
+#define BITCOIN_CUCKOOCACHE_H
#include <array>
#include <algorithm>
@@ -58,7 +58,7 @@ public:
* @post All calls to bit_is_set (without subsequent bit_unset) will return
* true.
*/
- bit_packed_atomic_flags(uint32_t size)
+ explicit bit_packed_atomic_flags(uint32_t size)
{
// pad out the size if needed
size = (size + 7) / 8;
@@ -478,4 +478,4 @@ public:
};
} // namespace CuckooCache
-#endif
+#endif // BITCOIN_CUCKOOCACHE_H
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 3e72c5bb9b..6ff740f581 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -2,11 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "dbwrapper.h"
+#include <dbwrapper.h>
-#include "fs.h"
-#include "util.h"
-#include "random.h"
+#include <random.h>
#include <leveldb/cache.h>
#include <leveldb/env.h>
@@ -19,7 +17,7 @@ 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 {
+ void Logv(const char * format, va_list ap) override {
if (!LogAcceptCategory(BCLog::LEVELDB)) {
return;
}
@@ -64,7 +62,7 @@ public:
assert(p <= limit);
base[std::min(bufsize - 1, (int)(p - base))] = '\0';
- LogPrintStr(base);
+ LogPrintf("leveldb: %s", base);
if (base != buffer) {
delete[] base;
}
@@ -190,7 +188,7 @@ bool CDBWrapper::IsEmpty()
}
CDBIterator::~CDBIterator() { delete piter; }
-bool CDBIterator::Valid() { return piter->Valid(); }
+bool CDBIterator::Valid() const { return piter->Valid(); }
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
void CDBIterator::Next() { piter->Next(); }
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 7575d207ae..9f4d4814eb 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -5,13 +5,13 @@
#ifndef BITCOIN_DBWRAPPER_H
#define BITCOIN_DBWRAPPER_H
-#include "clientversion.h"
-#include "fs.h"
-#include "serialize.h"
-#include "streams.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <clientversion.h>
+#include <fs.h>
+#include <serialize.h>
+#include <streams.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
@@ -22,7 +22,7 @@ static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
class dbwrapper_error : public std::runtime_error
{
public:
- dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
+ explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
class CDBWrapper;
@@ -61,7 +61,7 @@ public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
- CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
+ explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
void Clear()
{
@@ -130,7 +130,7 @@ public:
parent(_parent), piter(_piter) { };
~CDBIterator();
- bool Valid();
+ bool Valid() const;
void SeekToFirst();
diff --git a/src/fs.cpp b/src/fs.cpp
index a5e12f1cfc..570ed3e2ee 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -1,4 +1,4 @@
-#include "fs.h"
+#include <fs.h>
namespace fsbridge {
diff --git a/src/hash.cpp b/src/hash.cpp
index 5a15600be5..ea61764ded 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -2,10 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "hash.h"
-#include "crypto/common.h"
-#include "crypto/hmac_sha512.h"
-#include "pubkey.h"
+#include <hash.h>
+#include <crypto/common.h>
+#include <crypto/hmac_sha512.h>
inline uint32_t ROTL32(uint32_t x, int8_t r)
diff --git a/src/hash.h b/src/hash.h
index b9952d39fc..55724fb636 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_HASH_H
#define BITCOIN_HASH_H
-#include "crypto/ripemd160.h"
-#include "crypto/sha256.h"
-#include "prevector.h"
-#include "serialize.h"
-#include "uint256.h"
-#include "version.h"
+#include <crypto/ripemd160.h>
+#include <crypto/sha256.h>
+#include <prevector.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <version.h>
#include <vector>
@@ -88,20 +88,6 @@ inline uint256 Hash(const T1 p1begin, const T1 p1end,
return result;
}
-/** Compute the 256-bit hash of the concatenation of three objects. */
-template<typename T1, typename T2, typename T3>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end,
- const T3 p3begin, const T3 p3end) {
- static const unsigned char pblank[1] = {};
- uint256 result;
- CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
- .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
- .Write(p3begin == p3end ? pblank : (const unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0]))
- .Finalize((unsigned char*)&result);
- return result;
-}
-
/** Compute the 160-bit hash an object. */
template<typename T1>
inline uint160 Hash160(const T1 pbegin, const T1 pend)
@@ -168,7 +154,7 @@ private:
Source* source;
public:
- CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
+ explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
void read(char* pch, size_t nSize)
{
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index dd219c7291..6b6849e59b 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "httprpc.h"
-
-#include "base58.h"
-#include "chainparams.h"
-#include "httpserver.h"
-#include "rpc/protocol.h"
-#include "rpc/server.h"
-#include "random.h"
-#include "sync.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "ui_interface.h"
-#include "crypto/hmac_sha256.h"
+#include <httprpc.h>
+
+#include <base58.h>
+#include <chainparams.h>
+#include <httpserver.h>
+#include <rpc/protocol.h>
+#include <rpc/server.h>
+#include <random.h>
+#include <sync.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <ui_interface.h>
+#include <crypto/hmac_sha256.h>
#include <stdio.h>
#include <boost/algorithm/string.hpp> // boost::trim
@@ -43,7 +43,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
+ explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name() override
@@ -62,7 +62,7 @@ private:
/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
-static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;
+static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
@@ -192,7 +192,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
// array of requests
} else if (valRequest.isArray())
- strReply = JSONRPCExecBatch(valRequest.get_array());
+ strReply = JSONRPCExecBatch(jreq, valRequest.get_array());
else
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
@@ -238,8 +238,8 @@ bool StartHTTPRPC()
RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
#endif
assert(EventBase());
- httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
- RPCSetTimerInterface(httpRPCTimerInterface);
+ httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(EventBase());
+ RPCSetTimerInterface(httpRPCTimerInterface.get());
return true;
}
@@ -253,8 +253,7 @@ void StopHTTPRPC()
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
- RPCUnsetTimerInterface(httpRPCTimerInterface);
- delete httpRPCTimerInterface;
- httpRPCTimerInterface = 0;
+ RPCUnsetTimerInterface(httpRPCTimerInterface.get());
+ httpRPCTimerInterface.reset();
}
}
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 86b37f79bb..7d590f8e1f 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "httpserver.h"
+#include <httpserver.h>
-#include "chainparamsbase.h"
-#include "compat.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "netbase.h"
-#include "rpc/protocol.h" // For HTTP status codes
-#include "sync.h"
-#include "ui_interface.h"
+#include <chainparamsbase.h>
+#include <compat.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <netbase.h>
+#include <rpc/protocol.h> // For HTTP status codes
+#include <sync.h>
+#include <ui_interface.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,10 +24,11 @@
#include <event2/thread.h>
#include <event2/buffer.h>
+#include <event2/bufferevent.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
-#include "support/events.h"
+#include <support/events.h>
#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -40,7 +41,7 @@
static const size_t MAX_HEADERS_SIZE = 8192;
/** HTTP request work item */
-class HTTPWorkItem : public HTTPClosure
+class HTTPWorkItem final : public HTTPClosure
{
public:
HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
@@ -79,7 +80,7 @@ private:
{
public:
WorkQueue &wq;
- ThreadCounter(WorkQueue &w): wq(w)
+ explicit ThreadCounter(WorkQueue &w): wq(w)
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
@@ -93,7 +94,7 @@ private:
};
public:
- WorkQueue(size_t _maxDepth) : running(true),
+ explicit WorkQueue(size_t _maxDepth) : running(true),
maxDepth(_maxDepth),
numThreads(0)
{
@@ -164,13 +165,13 @@ struct HTTPPathHandler
/** HTTP module state */
//! libevent event loop
-static struct event_base* eventBase = 0;
+static struct event_base* eventBase = nullptr;
//! HTTP server
-struct evhttp* eventHTTP = 0;
+struct evhttp* eventHTTP = nullptr;
//! List of subnets to allow RPC connections from
static std::vector<CSubNet> rpc_allow_subnets;
//! Work queue for handling longer requests off the event loop thread
-static WorkQueue<HTTPClosure>* workQueue = 0;
+static WorkQueue<HTTPClosure>* workQueue = nullptr;
//! Handlers for (sub)paths
std::vector<HTTPPathHandler> pathHandlers;
//! Bound listening sockets
@@ -239,6 +240,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
+ // Disable reading to work around a libevent bug, fixed in 2.2.0.
+ if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
+ evhttp_connection* conn = evhttp_request_get_connection(req);
+ if (conn) {
+ bufferevent* bev = evhttp_connection_get_bufferevent(conn);
+ if (bev) {
+ bufferevent_disable(bev, EV_READ);
+ }
+ }
+ }
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
@@ -416,7 +427,7 @@ bool InitHTTPServer()
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
- // tranfer ownership to eventBase/HTTP via .release()
+ // transfer ownership to eventBase/HTTP via .release()
eventBase = base_ctr.release();
eventHTTP = http_ctr.release();
return true;
@@ -481,6 +492,8 @@ void StopHTTPServer()
}
if (eventBase) {
LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
+ // Exit the event loop as soon as there are no active events.
+ event_base_loopexit(eventBase, nullptr);
// Give event loop a few seconds to exit (to send back last RPC responses), then break it
// Before this was solved with event_base_loopexit, but that didn't work as expected in
// at least libevent 2.0.21 and always introduced a delay. In libevent
@@ -495,11 +508,11 @@ void StopHTTPServer()
}
if (eventHTTP) {
evhttp_free(eventHTTP);
- eventHTTP = 0;
+ eventHTTP = nullptr;
}
if (eventBase) {
event_base_free(eventBase);
- eventBase = 0;
+ eventBase = nullptr;
}
LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
}
@@ -599,11 +612,24 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
struct evbuffer* evb = evhttp_request_get_output_buffer(req);
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
- HTTPEvent* ev = new HTTPEvent(eventBase, true,
- std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr));
- ev->trigger(0);
+ auto req_copy = req;
+ HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
+ evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
+ // Re-enable reading from the socket. This is the second part of the libevent
+ // workaround above.
+ if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
+ evhttp_connection* conn = evhttp_request_get_connection(req_copy);
+ if (conn) {
+ bufferevent* bev = evhttp_connection_get_bufferevent(conn);
+ if (bev) {
+ bufferevent_enable(bev, EV_READ | EV_WRITE);
+ }
+ }
+ }
+ });
+ ev->trigger(nullptr);
replySent = true;
- req = 0; // transferred back to main thread
+ req = nullptr; // transferred back to main thread
}
CService HTTPRequest::GetPeer()
diff --git a/src/httpserver.h b/src/httpserver.h
index 3e434bf0a0..91ce5b4e00 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -61,7 +61,7 @@ private:
bool replySent;
public:
- HTTPRequest(struct evhttp_request* req);
+ explicit HTTPRequest(struct evhttp_request* req);
~HTTPRequest();
enum RequestMethod {
diff --git a/src/init.cpp b/src/init.cpp
index d79c2967b9..e4cad01b70 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -4,48 +4,49 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "init.h"
-
-#include "addrman.h"
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "compat/sanity.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "httpserver.h"
-#include "httprpc.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "netbase.h"
-#include "net.h"
-#include "net_processing.h"
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "rpc/server.h"
-#include "rpc/register.h"
-#include "rpc/blockchain.h"
-#include "script/standard.h"
-#include "script/sigcache.h"
-#include "scheduler.h"
-#include "timedata.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "torcontrol.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "validationinterface.h"
+#include <init.h>
+
+#include <addrman.h>
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <compat/sanity.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <httpserver.h>
+#include <httprpc.h>
+#include <key.h>
+#include <validation.h>
+#include <miner.h>
+#include <netbase.h>
+#include <net.h>
+#include <net_processing.h>
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <rpc/server.h>
+#include <rpc/register.h>
+#include <rpc/safemode.h>
+#include <rpc/blockchain.h>
+#include <script/standard.h>
+#include <script/sigcache.h>
+#include <scheduler.h>
+#include <timedata.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <torcontrol.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validationinterface.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include <wallet/init.h>
#endif
-#include "warnings.h"
+#include <warnings.h>
#include <stdint.h>
#include <stdio.h>
#include <memory>
@@ -63,13 +64,12 @@
#include <openssl/crypto.h>
#if ENABLE_ZMQ
-#include "zmq/zmqnotificationinterface.h"
+#include <zmq/zmqnotificationinterface.h>
#endif
bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
-static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
@@ -102,12 +102,11 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// created by AppInit() or the Qt main() function.
//
// A clean exit happens when StartShutdown() or the SIGTERM
-// signal handler sets fRequestShutdown, which triggers
-// the DetectShutdownThread(), which interrupts the main thread group.
-// DetectShutdownThread() then exits, which causes AppInit() to
-// continue (it .joins the shutdown thread).
-// Shutdown() is then
-// called to clean up database connections, and stop other
+// signal handler sets fRequestShutdown, which makes main thread's
+// WaitForShutdown() interrupts the thread group.
+// And then, WaitForShutdown() makes all other on-going threads
+// in the thread group join the main thread.
+// Shutdown() is then called to clean up database connections, and stop other
// threads that should only be stopped after the main network-processing
// threads have exited.
//
@@ -133,10 +132,10 @@ bool ShutdownRequested()
* chainstate, while keeping user interface out of the common library, which is shared
* between bitcoind, and bitcoin-qt and non-server tools.
*/
-class CCoinsViewErrorCatcher : public CCoinsViewBacked
+class CCoinsViewErrorCatcher final : public CCoinsViewBacked
{
public:
- CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
+ explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override {
try {
return CCoinsViewBacked::GetCoin(outpoint, coin);
@@ -153,7 +152,7 @@ public:
// Writes do not need similar protection, as failure to write is handled by the caller.
};
-static CCoinsViewErrorCatcher *pcoinscatcher = nullptr;
+static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
@@ -188,17 +187,18 @@ void Shutdown()
StopRPC();
StopHTTPServer();
#ifdef ENABLE_WALLET
- for (CWalletRef pwallet : vpwallets) {
- pwallet->Flush(false);
- }
+ FlushWallets();
#endif
MapPort(false);
- UnregisterValidationInterface(peerLogic.get());
+
+ // Because these depend on each-other, we make sure that neither can be
+ // using the other before destroying them.
+ if (peerLogic) UnregisterValidationInterface(peerLogic.get());
+ if (g_connman) g_connman->Stop();
peerLogic.reset();
g_connman.reset();
StopTorControl();
- UnregisterNodeSignals(GetNodeSignals());
if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool();
}
@@ -235,19 +235,13 @@ void Shutdown()
if (pcoinsTip != nullptr) {
FlushStateToDisk();
}
- delete pcoinsTip;
- pcoinsTip = nullptr;
- delete pcoinscatcher;
- pcoinscatcher = nullptr;
- delete pcoinsdbview;
- pcoinsdbview = nullptr;
- delete pblocktree;
- pblocktree = nullptr;
+ pcoinsTip.reset();
+ pcoinscatcher.reset();
+ pcoinsdbview.reset();
+ pblocktree.reset();
}
#ifdef ENABLE_WALLET
- for (CWalletRef pwallet : vpwallets) {
- pwallet->Flush(true);
- }
+ StopWallets();
#endif
#if ENABLE_ZMQ
@@ -267,11 +261,9 @@ void Shutdown()
#endif
UnregisterAllValidationInterfaces();
GetMainSignals().UnregisterBackgroundSignalScheduler();
+ GetMainSignals().UnregisterWithMempoolSignals(mempool);
#ifdef ENABLE_WALLET
- for (CWalletRef pwallet : vpwallets) {
- delete pwallet;
- }
- vpwallets.clear();
+ CloseWallets();
#endif
globalVerifyHandle.reset();
ECC_Stop();
@@ -317,15 +309,6 @@ void OnRPCStopped()
LogPrint(BCLog::RPC, "RPC stopped.\n");
}
-void OnRPCPreCommand(const CRPCCommand& cmd)
-{
- // Observe safe mode
- std::string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
- !cmd.okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
-}
-
std::string HelpMessage(HelpMessageMode mode)
{
const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
@@ -359,9 +342,13 @@ std::string HelpMessage(HelpMessageMode mode)
if (showDebug)
strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
+ strUsage += HelpMessageOpt("-debuglogfile=<file>", strprintf(_("Specify location of debug log file: this can be an absolute path or a path relative to the data directory (default: %s)"), DEFAULT_DEBUGLOGFILE));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex()));
+ }
strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL));
strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
@@ -380,11 +367,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX));
strUsage += HelpMessageGroup(_("Connection options:"));
- strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
+ strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info)"));
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD));
strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME));
strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections"));
+ strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections (the rules for this peer are the same as for -addnode)"));
strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"));
strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP));
strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"));
@@ -420,7 +407,7 @@ std::string HelpMessage(HelpMessageMode mode)
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
- strUsage += CWallet::GetWalletHelpString(showDebug);
+ strUsage += GetWalletHelpString(showDebug);
#endif
#if ENABLE_ZMQ
@@ -441,6 +428,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
+ strUsage += HelpMessageOpt("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used");
strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
@@ -479,7 +467,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug) {
- strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard()));
+ strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()));
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
}
@@ -494,7 +482,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Block creation options:"));
strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
- strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
+ strUsage += HelpMessageOpt("-blockmaxsize=<n>", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight"));
strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
if (showDebug)
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
@@ -547,20 +535,21 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex
return;
std::string strCmd = gArgs.GetArg("-blocknotify", "");
-
- boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
+ if (!strCmd.empty()) {
+ boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
}
static bool fHaveGenesis = false;
-static boost::mutex cs_GenesisWait;
+static CWaitableCriticalSection cs_GenesisWait;
static CConditionVariable condvar_GenesisWait;
static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
{
if (pBlockIndex != nullptr) {
{
- boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait);
+ WaitableLock lock_GenesisWait(cs_GenesisWait);
fHaveGenesis = true;
}
condvar_GenesisWait.notify_all();
@@ -597,7 +586,7 @@ void CleanupBlockRevFiles()
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
fs::path blocksdir = GetDataDir() / "blocks";
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
- if (is_regular_file(*it) &&
+ if (fs::is_regular_file(*it) &&
it->path().filename().string().length() == 12 &&
it->path().filename().string().substr(8,4) == ".dat")
{
@@ -720,7 +709,6 @@ bool AppInitServers(boost::thread_group& threadGroup)
{
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
- RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
return false;
if (!StartRPC())
@@ -796,6 +784,15 @@ void InitParameterInteraction()
if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
+
+ if (gArgs.IsArgSet("-blockmaxsize")) {
+ unsigned int max_size = gArgs.GetArg("-blockmaxsize", 0);
+ if (gArgs.SoftSetArg("blockmaxweight", strprintf("%d", max_size * WITNESS_SCALE_FACTOR))) {
+ LogPrintf("%s: parameter interaction: -blockmaxsize=%d -> setting -blockmaxweight=%d (-blockmaxsize is deprecated!)\n", __func__, max_size, max_size * WITNESS_SCALE_FACTOR);
+ } else {
+ LogPrintf("%s: Ignoring blockmaxsize setting which is overridden by blockmaxweight", __func__);
+ }
+ }
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
@@ -816,11 +813,10 @@ void InitLogging()
namespace { // Variables internal to initialization process only
-ServiceFlags nRelevantServices = NODE_NETWORK;
int nMaxConnections;
int nUserMaxConnections;
int nFD;
-ServiceFlags nLocalServices = NODE_NETWORK;
+ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
} // namespace
@@ -924,7 +920,8 @@ bool AppInitParameterInteraction()
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
const std::vector<std::string> categories = gArgs.GetArgs("-debug");
- if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
+ if (std::none_of(categories.begin(), categories.end(),
+ [](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) {
uint32_t flag = 0;
if (!GetLogCategory(&flag, &cat)) {
@@ -979,6 +976,20 @@ bool AppInitParameterInteraction()
else
LogPrintf("Validating signatures for all blocks.\n");
+ if (gArgs.IsArgSet("-minimumchainwork")) {
+ const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", "");
+ if (!IsHexNumber(minChainWorkStr)) {
+ return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr));
+ }
+ nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
+ } else {
+ nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
+ }
+ LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
+ if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
+ }
+
// mempool limits
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
@@ -1021,11 +1032,6 @@ bool AppInitParameterInteraction()
fPruneMode = true;
}
- RegisterAllCoreRPCCommands(tableRPC);
-#ifdef ENABLE_WALLET
- RegisterWalletRPCCommands(tableRPC);
-#endif
-
nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
@@ -1035,7 +1041,7 @@ bool AppInitParameterInteraction()
if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
}
- // High fee check is done afterward in CWallet::ParameterInteraction()
+ // High fee check is done afterward in WalletParameterInteraction()
::minRelayTxFee = CFeeRate(n);
} else if (incrementalRelayFee > ::minRelayTxFee) {
// Allow only setting incrementalRelayFee to control both
@@ -1068,7 +1074,7 @@ bool AppInitParameterInteraction()
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
#ifdef ENABLE_WALLET
- if (!CWallet::ParameterInteraction())
+ if (!WalletParameterInteraction())
return false;
#endif
@@ -1204,8 +1210,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
ShrinkDebugFile();
}
- if (fPrintToDebugLog)
- OpenDebugLog();
+ if (fPrintToDebugLog) {
+ if (!OpenDebugLog()) {
+ return InitError(strprintf("Could not open debug log file %s", GetDebugLogPath().string()));
+ }
+ }
if (!fLogTimestamps)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
@@ -1228,6 +1237,15 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+ GetMainSignals().RegisterWithMempoolSignals(mempool);
+
+ /* Register RPC commands regardless of -server setting so they will be
+ * available in the GUI RPC console even if external calls are disabled.
+ */
+ RegisterAllCoreRPCCommands(tableRPC);
+#ifdef ENABLE_WALLET
+ RegisterWalletRPC(tableRPC);
+#endif
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1245,7 +1263,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
- if (!CWallet::Verify())
+ if (!VerifyWallets())
return false;
#endif
// ********************************************************* Step 6: network initialization
@@ -1258,9 +1276,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
CConnman& connman = *g_connman;
- peerLogic.reset(new PeerLogicValidation(&connman));
+ peerLogic.reset(new PeerLogicValidation(&connman, scheduler));
RegisterValidationInterface(peerLogic.get());
- RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
@@ -1395,12 +1412,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
do {
try {
UnloadBlockIndex();
- delete pcoinsTip;
- delete pcoinsdbview;
- delete pcoinscatcher;
- delete pblocktree;
-
- pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset);
+ pcoinsTip.reset();
+ pcoinsdbview.reset();
+ pcoinscatcher.reset();
+ pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
if (fReset) {
pblocktree->WriteReindexing(true);
@@ -1428,7 +1443,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Check for changed -txindex state
if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
+ strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
break;
}
@@ -1451,8 +1466,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// At this point we're either in reindex or we've loaded a useful
// block tree into mapBlockIndex!
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState);
- pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
+ pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
+ pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
@@ -1462,13 +1477,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!ReplayBlocks(chainparams, pcoinsdbview)) {
+ if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break;
}
// The on-disk coinsdb is now in a good state, create the cache
- pcoinsTip = new CCoinsViewCache(pcoinscatcher);
+ pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
if (!is_coinsview_empty) {
@@ -1510,7 +1525,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
break;
@@ -1566,7 +1581,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
- if (!CWallet::InitLoadWallet())
+ if (!OpenWallets())
return false;
#else
LogPrintf("No wallet support compiled in!\n");
@@ -1592,9 +1607,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Note that setting NODE_WITNESS is never required: the only downside from not
// doing so is that after activation, no upgraded nodes will fetch from you.
nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
- // Only care about others providing witness capabilities if there is a softfork
- // defined.
- nRelevantServices = ServiceFlags(nRelevantServices | NODE_WITNESS);
}
// ********************************************************* Step 10: import blocks
@@ -1622,7 +1634,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Wait for genesis block to be processed
{
- boost::unique_lock<boost::mutex> lock(cs_GenesisWait);
+ WaitableLock lock(cs_GenesisWait);
while (!fHaveGenesis) {
condvar_GenesisWait.wait(lock);
}
@@ -1631,9 +1643,16 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 11: start node
+ int chain_active_height;
+
//// debug print
- LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
- LogPrintf("nBestHeight = %d\n", chainActive.Height());
+ {
+ LOCK(cs_main);
+ LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
+ chain_active_height = chainActive.Height();
+ }
+ LogPrintf("nBestHeight = %d\n", chain_active_height);
+
if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
@@ -1644,15 +1663,16 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
- connOptions.nRelevantServices = nRelevantServices;
connOptions.nMaxConnections = nMaxConnections;
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
connOptions.nMaxFeeler = 1;
- connOptions.nBestHeight = chainActive.Height();
+ connOptions.nBestHeight = chain_active_height;
connOptions.uiInterface = &uiInterface;
+ connOptions.m_msgproc = peerLogic.get();
connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+ connOptions.m_added_nodes = gArgs.GetArgs("-addnode");
connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
@@ -1683,10 +1703,16 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
connOptions.vWhitelistedRange.push_back(subnet);
}
- if (gArgs.IsArgSet("-seednode")) {
- connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
- }
+ connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
+ // Initiate outbound connections unless connect=0
+ connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect");
+ if (!connOptions.m_use_addrman_outgoing) {
+ const auto connect = gArgs.GetArgs("-connect");
+ if (connect.size() != 1 || connect[0] != "0") {
+ connOptions.m_specified_outgoing = connect;
+ }
+ }
if (!connman.Start(scheduler, connOptions)) {
return false;
}
@@ -1697,10 +1723,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Done loading"));
#ifdef ENABLE_WALLET
- for (CWalletRef pwallet : vpwallets) {
- pwallet->postInitProcess(scheduler);
- }
+ StartWallets(scheduler);
#endif
- return !fRequestShutdown;
+ return true;
}
diff --git a/src/key.cpp b/src/key.cpp
index 315a3978c8..9d4c4498d8 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -2,13 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
+#include <key.h>
-#include "arith_uint256.h"
-#include "crypto/common.h"
-#include "crypto/hmac_sha512.h"
-#include "pubkey.h"
-#include "random.h"
+#include <arith_uint256.h>
+#include <crypto/common.h>
+#include <crypto/hmac_sha512.h>
+#include <random.h>
#include <secp256k1.h>
#include <secp256k1_recovery.h>
diff --git a/src/key.h b/src/key.h
index 2c6f151727..c610e5e6cd 100644
--- a/src/key.h
+++ b/src/key.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
-#include "pubkey.h"
-#include "serialize.h"
-#include "support/allocators/secure.h"
-#include "uint256.h"
+#include <pubkey.h>
+#include <serialize.h>
+#include <support/allocators/secure.h>
+#include <uint256.h>
#include <stdexcept>
#include <vector>
@@ -56,11 +56,6 @@ public:
keydata.resize(32);
}
- //! Destructor (again necessary because of memlocking).
- ~CKey()
- {
- }
-
friend bool operator==(const CKey& a, const CKey& b)
{
return a.fCompressed == b.fCompressed &&
@@ -172,6 +167,8 @@ struct CExtKey {
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
+ if (len != BIP32_EXTKEY_SIZE)
+ throw std::runtime_error("Invalid extended key size\n");
s.read((char *)&code[0], len);
Decode(code);
}
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 8454175ca8..4ab089e032 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -3,11 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "keystore.h"
+#include <keystore.h>
-#include "key.h"
-#include "pubkey.h"
-#include "util.h"
+#include <util.h>
bool CKeyStore::AddKey(const CKey &key) {
return AddKeyPubKey(key, key.GetPubKey());
@@ -36,6 +34,33 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
return true;
}
+bool CBasicKeyStore::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ return mapKeys.count(address) > 0;
+}
+
+std::set<CKeyID> CBasicKeyStore::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
+}
+
+bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
+{
+ LOCK(cs_KeyStore);
+ KeyMap::const_iterator mi = mapKeys.find(address);
+ if (mi != mapKeys.end()) {
+ keyOut = mi->second;
+ return true;
+ }
+ return false;
+}
+
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
diff --git a/src/keystore.h b/src/keystore.h
index 965ae0c79a..4e6d8e8a27 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
-#include "key.h"
-#include "pubkey.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "sync.h"
+#include <key.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
#include <boost/signals2/signal.hpp>
@@ -30,7 +30,7 @@ public:
//! Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
- virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
+ virtual std::set<CKeyID> GetKeys() const =0;
virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const =0;
//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
@@ -62,49 +62,17 @@ protected:
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- bool HaveKey(const CKeyID &address) const override
- {
- bool result;
- {
- LOCK(cs_KeyStore);
- result = (mapKeys.count(address) > 0);
- }
- return result;
- }
- void GetKeys(std::set<CKeyID> &setAddress) const override
- {
- setAddress.clear();
- {
- LOCK(cs_KeyStore);
- KeyMap::const_iterator mi = mapKeys.begin();
- while (mi != mapKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
- }
- }
- }
- bool GetKey(const CKeyID &address, CKey &keyOut) const override
- {
- {
- LOCK(cs_KeyStore);
- KeyMap::const_iterator mi = mapKeys.find(address);
- if (mi != mapKeys.end())
- {
- keyOut = mi->second;
- return true;
- }
- }
- return false;
- }
- virtual bool AddCScript(const CScript& redeemScript) override;
- virtual bool HaveCScript(const CScriptID &hash) const override;
- virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
+ bool HaveKey(const CKeyID &address) const override;
+ std::set<CKeyID> GetKeys() const override;
+ bool GetKey(const CKeyID &address, CKey &keyOut) const override;
+ bool AddCScript(const CScript& redeemScript) override;
+ bool HaveCScript(const CScriptID &hash) const override;
+ bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
- virtual bool AddWatchOnly(const CScript &dest) override;
- virtual bool RemoveWatchOnly(const CScript &dest) override;
- virtual bool HaveWatchOnly(const CScript &dest) const override;
- virtual bool HaveWatchOnly() const override;
+ bool AddWatchOnly(const CScript &dest) override;
+ bool RemoveWatchOnly(const CScript &dest) override;
+ bool HaveWatchOnly(const CScript &dest) const override;
+ bool HaveWatchOnly() const override;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
diff --git a/src/limitedmap.h b/src/limitedmap.h
index e9dcb6defd..7afc8b458d 100644
--- a/src/limitedmap.h
+++ b/src/limitedmap.h
@@ -27,7 +27,7 @@ protected:
size_type nMaxSize;
public:
- limitedmap(size_type nMaxSizeIn)
+ explicit limitedmap(size_type nMaxSizeIn)
{
assert(nMaxSizeIn > 0);
nMaxSize = nMaxSizeIn;
diff --git a/src/memusage.h b/src/memusage.h
index 93fd6a0eb5..d931171d35 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_MEMUSAGE_H
#define BITCOIN_MEMUSAGE_H
-#include "indirectmap.h"
+#include <indirectmap.h>
#include <stdlib.h>
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index f0abea0611..f4db9dd57e 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -3,39 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "merkleblock.h"
+#include <merkleblock.h>
-#include "hash.h"
-#include "consensus/consensus.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <consensus/consensus.h>
+#include <utilstrencodings.h>
-CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
-{
- header = block.GetBlockHeader();
- std::vector<bool> vMatch;
- std::vector<uint256> vHashes;
-
- vMatch.reserve(block.vtx.size());
- vHashes.reserve(block.vtx.size());
-
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- {
- const uint256& hash = block.vtx[i]->GetHash();
- if (filter.IsRelevantAndUpdate(*block.vtx[i]))
- {
- vMatch.push_back(true);
- vMatchedTxn.push_back(std::make_pair(i, hash));
- }
- else
- vMatch.push_back(false);
- vHashes.push_back(hash);
- }
-
- txn = CPartialMerkleTree(vHashes, vMatch);
-}
-
-CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
+CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
{
header = block.GetBlockHeader();
@@ -48,10 +23,14 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const uint256& hash = block.vtx[i]->GetHash();
- if (txids.count(hash))
+ if (txids && txids->count(hash)) {
vMatch.push_back(true);
- else
+ } else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) {
+ vMatch.push_back(true);
+ vMatchedTxn.emplace_back(i, hash);
+ } else {
vMatch.push_back(false);
+ }
vHashes.push_back(hash);
}
diff --git a/src/merkleblock.h b/src/merkleblock.h
index f590c487de..b64c34370e 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_MERKLEBLOCK_H
#define BITCOIN_MERKLEBLOCK_H
-#include "serialize.h"
-#include "uint256.h"
-#include "primitives/block.h"
-#include "bloom.h"
+#include <serialize.h>
+#include <uint256.h>
+#include <primitives/block.h>
+#include <bloom.h>
#include <vector>
@@ -63,7 +63,7 @@ protected:
bool fBad;
/** helper function to efficiently calculate the number of nodes at given height in the merkle tree */
- unsigned int CalcTreeWidth(int height) {
+ unsigned int CalcTreeWidth(int height) const {
return (nTransactions+(1 << height)-1) >> height;
}
@@ -131,8 +131,12 @@ public:
CBlockHeader header;
CPartialMerkleTree txn;
-public:
- /** Public only for unit testing and relay testing (not relayed) */
+ /**
+ * Public only for unit testing and relay testing (not relayed).
+ *
+ * Used only when a bloom filter is specified to allow
+ * testing the transactions which matched the bloom filter.
+ */
std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
/**
@@ -140,10 +144,10 @@ public:
* Note that this will call IsRelevantAndUpdate on the filter for each transaction,
* thus the filter will likely be modified.
*/
- CMerkleBlock(const CBlock& block, CBloomFilter& filter);
+ CMerkleBlock(const CBlock& block, CBloomFilter& filter) : CMerkleBlock(block, &filter, nullptr) { }
// Create from a CBlock, matching the txids in the set
- CMerkleBlock(const CBlock& block, const std::set<uint256>& txids);
+ CMerkleBlock(const CBlock& block, const std::set<uint256>& txids) : CMerkleBlock(block, nullptr, &txids) { }
CMerkleBlock() {}
@@ -154,6 +158,10 @@ public:
READWRITE(header);
READWRITE(txn);
}
+
+private:
+ // Combined constructor to consolidate code
+ CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids);
};
#endif // BITCOIN_MERKLEBLOCK_H
diff --git a/src/miner.cpp b/src/miner.cpp
index 403d3d4e4a..0fb9b774d3 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -3,29 +3,28 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "miner.h"
-
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "consensus/tx_verify.h"
-#include "consensus/merkle.h"
-#include "consensus/validation.h"
-#include "hash.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/feerate.h"
-#include "policy/policy.h"
-#include "pow.h"
-#include "primitives/transaction.h"
-#include "script/standard.h"
-#include "timedata.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "validationinterface.h"
+#include <miner.h>
+
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <consensus/tx_verify.h>
+#include <consensus/merkle.h>
+#include <consensus/validation.h>
+#include <hash.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <pow.h>
+#include <primitives/transaction.h>
+#include <script/standard.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validationinterface.h>
#include <algorithm>
#include <queue>
@@ -43,7 +42,6 @@
// its ancestors.
uint64_t nLastBlockTx = 0;
-uint64_t nLastBlockSize = 0;
uint64_t nLastBlockWeight = 0;
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
@@ -64,7 +62,6 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
BlockAssembler::Options::Options() {
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
- nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
}
BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)
@@ -72,10 +69,6 @@ BlockAssembler::BlockAssembler(const CChainParams& params, const Options& option
blockMinFeeRate = options.blockMinFeeRate;
// Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
- // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
- nBlockMaxSize = std::max<size_t>(1000, std::min<size_t>(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize));
- // Whether we need to account for byte usage (in addition to weight usage)
- fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000);
}
static BlockAssembler::Options DefaultOptions(const CChainParams& params)
@@ -85,20 +78,7 @@ static BlockAssembler::Options DefaultOptions(const CChainParams& params)
// If only one is given, only restrict the specified resource.
// If both are given, restrict both.
BlockAssembler::Options options;
- options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
- options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
- bool fWeightSet = false;
- if (gArgs.IsArgSet("-blockmaxweight")) {
- options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
- options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
- fWeightSet = true;
- }
- if (gArgs.IsArgSet("-blockmaxsize")) {
- options.nBlockMaxSize = gArgs.GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
- if (!fWeightSet) {
- options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR;
- }
- }
+ options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
if (gArgs.IsArgSet("-blockmintxfee")) {
CAmount n = 0;
ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n);
@@ -116,7 +96,6 @@ void BlockAssembler::resetBlock()
inBlock.clear();
// Reserve space for coinbase tx
- nBlockSize = 1000;
nBlockWeight = 4000;
nBlockSigOpsCost = 400;
fIncludeWitness = false;
@@ -145,6 +124,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
+ assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
@@ -175,7 +155,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
int64_t nTime1 = GetTimeMicros();
nLastBlockTx = nBlockTx;
- nLastBlockSize = nBlockSize;
nLastBlockWeight = nBlockWeight;
// Create coinbase transaction.
@@ -190,8 +169,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
pblocktemplate->vTxFees[0] = -nFees;
- uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
- LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
+ LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
@@ -224,7 +202,7 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
}
}
-bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost)
+bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const
{
// TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight)
@@ -238,22 +216,13 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// - transaction finality (locktime)
// - premature witness (in case segwit transactions are added to mempool before
// segwit activation)
-// - serialized size (in case -blockmaxsize is in use)
bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
{
- uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting
for (const CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
if (!fIncludeWitness && it->GetTx().HasWitness())
return false;
- if (fNeedSizeAccounting) {
- uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
- if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) {
- return false;
- }
- nPotentialBlockSize += nTxSize;
- }
}
return true;
}
@@ -263,9 +232,6 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
pblock->vtx.emplace_back(iter->GetSharedTx());
pblocktemplate->vTxFees.push_back(iter->GetFee());
pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());
- if (fNeedSizeAccounting) {
- nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
- }
nBlockWeight += iter->GetTxWeight();
++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost();
diff --git a/src/miner.h b/src/miner.h
index 5c9cfd78f0..d81ec6421c 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -6,13 +6,13 @@
#ifndef BITCOIN_MINER_H
#define BITCOIN_MINER_H
-#include "primitives/block.h"
-#include "txmempool.h"
+#include <primitives/block.h>
+#include <txmempool.h>
#include <stdint.h>
#include <memory>
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
class CBlockIndex;
class CChainParams;
@@ -33,7 +33,7 @@ struct CBlockTemplate
// Container for tracking updates to ancestor feerate as we include (parent)
// transactions in a block
struct CTxMemPoolModifiedEntry {
- CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
+ explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
{
iter = entry;
nSizeWithAncestors = entry->GetSizeWithAncestors();
@@ -71,7 +71,7 @@ struct modifiedentry_iter {
// except operating on CTxMemPoolModifiedEntry.
// TODO: refactor to avoid duplication of this logic.
struct CompareModifiedEntry {
- bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b)
+ bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b) const
{
double f1 = (double)a.nModFeesWithAncestors * b.nSizeWithAncestors;
double f2 = (double)b.nModFeesWithAncestors * a.nSizeWithAncestors;
@@ -86,7 +86,7 @@ struct CompareModifiedEntry {
// This is sufficient to sort an ancestor package in an order that is valid
// to appear in a block.
struct CompareTxIterByAncestorCount {
- bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b)
+ bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b) const
{
if (a->GetCountWithAncestors() != b->GetCountWithAncestors())
return a->GetCountWithAncestors() < b->GetCountWithAncestors();
@@ -116,7 +116,7 @@ typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator
struct update_for_parent_inclusion
{
- update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
+ explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
void operator() (CTxMemPoolModifiedEntry &e)
{
@@ -139,13 +139,11 @@ private:
// Configuration parameters for the block size
bool fIncludeWitness;
- unsigned int nBlockMaxWeight, nBlockMaxSize;
- bool fNeedSizeAccounting;
+ unsigned int nBlockMaxWeight;
CFeeRate blockMinFeeRate;
// Information on the current status of the block
uint64_t nBlockWeight;
- uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
CAmount nFees;
@@ -160,11 +158,10 @@ public:
struct Options {
Options();
size_t nBlockMaxWeight;
- size_t nBlockMaxSize;
CFeeRate blockMinFeeRate;
};
- BlockAssembler(const CChainParams& params);
+ explicit BlockAssembler(const CChainParams& params);
BlockAssembler(const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
@@ -187,7 +184,7 @@ private:
/** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
/** Test if a new package would "fit" in the block */
- bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost);
+ bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const;
/** Perform checks on each transaction in a package:
* locktime, premature-witness, serialized size (if necessary)
* These checks should always succeed, and they're here
diff --git a/src/net.cpp b/src/net.cpp
index 599a6128fa..23bf640472 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -4,23 +4,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "net.h"
-
-#include "addrman.h"
-#include "chainparams.h"
-#include "clientversion.h"
-#include "consensus/consensus.h"
-#include "crypto/common.h"
-#include "crypto/sha256.h"
-#include "hash.h"
-#include "primitives/transaction.h"
-#include "netbase.h"
-#include "scheduler.h"
-#include "ui_interface.h"
-#include "utilstrencodings.h"
+#include <net.h>
+
+#include <chainparams.h>
+#include <clientversion.h>
+#include <consensus/consensus.h>
+#include <crypto/common.h>
+#include <crypto/sha256.h>
+#include <primitives/transaction.h>
+#include <netbase.h>
+#include <scheduler.h>
+#include <ui_interface.h>
+#include <utilstrencodings.h>
#ifdef WIN32
#include <string.h>
@@ -89,10 +87,6 @@ std::string strSubVersion;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-// Signals for message handling
-static CNodeSignals g_signals;
-CNodeSignals& GetNodeSignals() { return g_signals; }
-
void CConnman::AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
@@ -114,13 +108,13 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
int nBestReachability = -1;
{
LOCK(cs_mapLocalHost);
- for (std::map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
+ for (const auto& entry : mapLocalHost)
{
- int nScore = (*it).second.nScore;
- int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
+ int nScore = entry.second.nScore;
+ int nReachability = entry.first.GetReachabilityFrom(paddrPeer);
if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
{
- addr = CService((*it).first, (*it).second.nPort);
+ addr = CService(entry.first, entry.second.nPort);
nBestReachability = nReachability;
nBestScore = nScore;
}
@@ -139,11 +133,10 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
const int64_t nOneWeek = 7*24*60*60;
std::vector<CAddress> vSeedsOut;
vSeedsOut.reserve(vSeedsIn.size());
- for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i)
- {
+ for (const auto& seed_in : vSeedsIn) {
struct in6_addr ip;
- memcpy(&ip, i->addr, sizeof(ip));
- CAddress addr(CService(ip, i->port), NODE_NETWORK);
+ memcpy(&ip, seed_in.addr, sizeof(ip));
+ CAddress addr(CService(ip, seed_in.port), NODE_NETWORK);
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
vSeedsOut.push_back(addr);
}
@@ -303,18 +296,22 @@ bool IsReachable(const CNetAddr& addr)
CNode* CConnman::FindNode(const CNetAddr& ip)
{
LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
- if ((CNetAddr)pnode->addr == ip)
- return (pnode);
+ for (CNode* pnode : vNodes) {
+ if ((CNetAddr)pnode->addr == ip) {
+ return pnode;
+ }
+ }
return nullptr;
}
CNode* CConnman::FindNode(const CSubNet& subNet)
{
LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
- if (subNet.Match((CNetAddr)pnode->addr))
- return (pnode);
+ for (CNode* pnode : vNodes) {
+ if (subNet.Match((CNetAddr)pnode->addr)) {
+ return pnode;
+ }
+ }
return nullptr;
}
@@ -323,7 +320,7 @@ CNode* CConnman::FindNode(const std::string& addrName)
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (pnode->GetAddrName() == addrName) {
- return (pnode);
+ return pnode;
}
}
return nullptr;
@@ -332,9 +329,11 @@ CNode* CConnman::FindNode(const std::string& addrName)
CNode* CConnman::FindNode(const CService& addr)
{
LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
- if ((CService)pnode->addr == addr)
- return (pnode);
+ for (CNode* pnode : vNodes) {
+ if ((CService)pnode->addr == addr) {
+ return pnode;
+ }
+ }
return nullptr;
}
@@ -384,19 +383,16 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pszDest ? pszDest : addrConnect.ToString(),
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
- // Connect
- SOCKET hSocket;
- bool proxyConnectionFailed = false;
- if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
- ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
- {
- if (!IsSelectableSocket(hSocket)) {
- LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
- CloseSocket(hSocket);
- return nullptr;
- }
-
- if (pszDest && addrConnect.IsValid()) {
+ // Resolve
+ const int default_port = Params().GetDefaultPort();
+ if (pszDest) {
+ std::vector<CService> resolved;
+ if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
+ addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE);
+ if (!addrConnect.IsValid()) {
+ LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s", addrConnect.ToString(), pszDest);
+ return nullptr;
+ }
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created, and return the existing CNode instead.
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
@@ -406,30 +402,61 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (pnode)
{
pnode->MaybeSetAddrName(std::string(pszDest));
- CloseSocket(hSocket);
LogPrintf("Failed to open new connection, already connected\n");
return nullptr;
}
}
+ }
- addrman.Attempt(addrConnect, fCountFailure);
-
- // Add node
- NodeId id = GetNewNodeId();
- uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
- CAddress addr_bind = GetBindAddress(hSocket);
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
- pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
- pnode->AddRef();
+ // Connect
+ bool connected = false;
+ SOCKET hSocket;
+ proxyType proxy;
+ if (addrConnect.IsValid()) {
+ bool proxyConnectionFailed = false;
- return pnode;
- } else if (!proxyConnectionFailed) {
- // If connecting to the node failed, and failure is not caused by a problem connecting to
- // the proxy, mark this as an attempt.
- addrman.Attempt(addrConnect, fCountFailure);
+ if (GetProxy(addrConnect.GetNetwork(), proxy)) {
+ hSocket = CreateSocket(proxy.proxy);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
+ connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed);
+ } else {
+ // no proxy needed (none set for target network)
+ hSocket = CreateSocket(addrConnect);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
+ connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout);
+ }
+ if (!proxyConnectionFailed) {
+ // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
+ // the proxy, mark this as an attempt.
+ addrman.Attempt(addrConnect, fCountFailure);
+ }
+ } else if (pszDest && GetNameProxy(proxy)) {
+ hSocket = CreateSocket(proxy.proxy);
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
+ std::string host;
+ int port = default_port;
+ SplitHostPort(std::string(pszDest), port, host);
+ connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr);
+ }
+ if (!connected) {
+ CloseSocket(hSocket);
+ return nullptr;
}
- return nullptr;
+ // Add node
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+ CAddress addr_bind = GetBindAddress(hSocket);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
+ pnode->AddRef();
+
+ return pnode;
}
void CConnman::DumpBanlist()
@@ -478,10 +505,9 @@ void CConnman::ClearBanned()
bool CConnman::IsBanned(CNetAddr ip)
{
LOCK(cs_setBanned);
- for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++)
- {
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
+ for (const auto& it : setBanned) {
+ CSubNet subNet = it.first;
+ CBanEntry banEntry = it.second;
if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
return true;
@@ -665,7 +691,7 @@ void CNode::copyStats(CNodeStats &stats)
X(cleanSubVer);
}
X(fInbound);
- X(fAddnode);
+ X(m_manual_connection);
X(nStartingHeight);
{
LOCK(cs_vSend);
@@ -942,6 +968,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
return a.nTimeConnected > b.nTimeConnected;
}
+
+//! Sort an array by the specified comparator, then erase the last K elements.
+template<typename T, typename Comparator>
+static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, size_t k)
+{
+ std::sort(elements.begin(), elements.end(), comparator);
+ size_t eraseSize = std::min(k, elements.size());
+ elements.erase(elements.end() - eraseSize, elements.end());
+}
+
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning.
@@ -956,7 +992,7 @@ bool CConnman::AttemptToEvictConnection()
{
LOCK(cs_vNodes);
- for (CNode *node : vNodes) {
+ for (const CNode* node : vNodes) {
if (node->fWhitelisted)
continue;
if (!node->fInbound)
@@ -965,48 +1001,29 @@ bool CConnman::AttemptToEvictConnection()
continue;
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
- (node->nServices & nRelevantServices) == nRelevantServices,
+ HasAllDesirableServiceFlags(node->nServices),
node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
}
- if (vEvictionCandidates.empty()) return false;
-
// Protect connections with certain characteristics
// Deterministically select 4 peers to protect by netgroup.
// An attacker cannot predict which netgroups will be protected
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
// Protect the 8 nodes with the lowest minimum ping time.
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
// Protect 4 nodes that most recently sent us transactions.
// An attacker cannot manipulate this metric without performing useful work.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
// Protect 4 nodes that most recently sent us blocks.
// An attacker cannot manipulate this metric without performing useful work.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
// Protect the half of the remaining nodes which have been connected the longest.
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
- vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
+ EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);
if (vEvictionCandidates.empty()) return false;
@@ -1017,12 +1034,12 @@ bool CConnman::AttemptToEvictConnection()
int64_t nMostConnectionsTime = 0;
std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
for (const NodeEvictionCandidate &node : vEvictionCandidates) {
- mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);
- int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;
- size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();
+ std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
+ group.push_back(node);
+ int64_t grouptime = group[0].nTimeConnected;
- if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
- nMostConnections = groupsize;
+ if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
+ nMostConnections = group.size();
nMostConnectionsTime = grouptime;
naMostConnections = node.nKeyedNetGroup;
}
@@ -1034,9 +1051,9 @@ bool CConnman::AttemptToEvictConnection()
// Disconnect from the network group with the most connections
NodeId evicted = vEvictionCandidates.front().id;
LOCK(cs_vNodes);
- for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
- if ((*it)->GetId() == evicted) {
- (*it)->fDisconnect = true;
+ for (CNode* pnode : vNodes) {
+ if (pnode->GetId() == evicted) {
+ pnode->fDisconnect = true;
return true;
}
}
@@ -1060,9 +1077,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
- if (pnode->fInbound)
- nInbound++;
+ for (const CNode* pnode : vNodes) {
+ if (pnode->fInbound) nInbound++;
+ }
}
if (hSocket == INVALID_SOCKET)
@@ -1092,7 +1109,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
if (IsBanned(addr) && !whitelisted)
{
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
return;
}
@@ -1114,7 +1131,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
- GetNodeSignals().InitializeNode(pnode, *this);
+ m_msgproc->InitializeNode(pnode);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1438,9 +1455,9 @@ void CConnman::WakeMessageHandler()
void ThreadMapPort()
{
std::string port = strprintf("%u", GetListenPort());
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- struct UPNPDev * devlist = 0;
+ const char * multicastif = nullptr;
+ const char * minissdpdpath = nullptr;
+ struct UPNPDev * devlist = nullptr;
char lanaddr[64];
#ifndef UPNPDISCOVER_SUCCESS
@@ -1510,13 +1527,13 @@ void ThreadMapPort()
{
r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
- freeUPNPDevlist(devlist); devlist = 0;
+ freeUPNPDevlist(devlist); devlist = nullptr;
FreeUPNPUrls(&urls);
throw;
}
} else {
LogPrintf("No valid UPnP IGDs found\n");
- freeUPNPDevlist(devlist); devlist = 0;
+ freeUPNPDevlist(devlist); devlist = nullptr;
if (r != 0)
FreeUPNPUrls(&urls);
}
@@ -1524,22 +1541,20 @@ void ThreadMapPort()
void MapPort(bool fUseUPnP)
{
- static boost::thread* upnp_thread = nullptr;
+ static std::unique_ptr<boost::thread> upnp_thread;
if (fUseUPnP)
{
if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
- delete upnp_thread;
}
- upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort));
+ upnp_thread.reset(new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
}
else if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
- delete upnp_thread;
- upnp_thread = nullptr;
+ upnp_thread.reset();
}
}
@@ -1582,7 +1597,7 @@ void CConnman::ThreadDNSAddressSeed()
LOCK(cs_vNodes);
int nRelevant = 0;
for (auto pnode : vNodes) {
- nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
+ nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
}
if (nRelevant >= 2) {
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
@@ -1604,7 +1619,7 @@ void CConnman::ThreadDNSAddressSeed()
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
- ServiceFlags requiredServiceBits = nRelevantServices;
+ ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
std::string host = GetDNSHost(seed, &requiredServiceBits);
CNetAddr resolveSource;
if (!resolveSource.SetInternal(host)) {
@@ -1674,18 +1689,49 @@ void CConnman::ProcessOneShot()
}
}
-void CConnman::ThreadOpenConnections()
+bool CConnman::GetTryNewOutboundPeer()
+{
+ return m_try_another_outbound_peer;
+}
+
+void CConnman::SetTryNewOutboundPeer(bool flag)
+{
+ m_try_another_outbound_peer = flag;
+ LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false");
+}
+
+// Return the number of peers we have over our outbound connection limit
+// Exclude peers that are marked for disconnect, or are going to be
+// disconnected soon (eg one-shots and feelers)
+// Also exclude peers that haven't finished initial connection handshake yet
+// (so that we don't decide we're over our desired connection limit, and then
+// evict some peer that has finished the handshake)
+int CConnman::GetExtraOutboundCount()
+{
+ int nOutbound = 0;
+ {
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodes) {
+ if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) {
+ ++nOutbound;
+ }
+ }
+ }
+ return std::max(nOutbound - nMaxOutbound, 0);
+}
+
+void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
// Connect to specific addresses
- if (gArgs.IsArgSet("-connect"))
+ if (!connect.empty())
{
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- for (const std::string& strAddr : gArgs.GetArgs("-connect"))
+ for (const std::string& strAddr : connect)
{
CAddress addr(CService(), NODE_NONE);
- OpenNetworkConnection(addr, false, nullptr, strAddr.c_str());
+ OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), false, false, true);
for (int i = 0; i < 10 && i < nLoop; i++)
{
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
@@ -1733,17 +1779,11 @@ void CConnman::ThreadOpenConnections()
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
- int nOutboundRelevant = 0;
std::set<std::vector<unsigned char> > setConnected;
{
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
- if (!pnode->fInbound && !pnode->fAddnode) {
-
- // Count the peers that have all relevant services
- if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) {
- nOutboundRelevant++;
- }
+ if (!pnode->fInbound && !pnode->m_manual_connection) {
// Netgroups for inbound and addnode peers are not excluded because our goal here
// is to not use multiple of our limited outbound slots on a single netgroup
// but inbound and addnode peers do not use our outbound slots. Inbound peers
@@ -1768,7 +1808,8 @@ void CConnman::ThreadOpenConnections()
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false;
- if (nOutbound >= nMaxOutbound) {
+
+ if (nOutbound >= nMaxOutbound && !GetTryNewOutboundPeer()) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
@@ -1798,21 +1839,16 @@ void CConnman::ThreadOpenConnections()
if (IsLimited(addr))
continue;
- // only connect to full nodes
- if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
- continue;
-
// only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up.
- ServiceFlags nRequiredServices = nRelevantServices;
- if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) {
- nRequiredServices = REQUIRED_SERVICES;
- }
-
- if ((addr.nServices & nRequiredServices) != nRequiredServices) {
+ // for non-feelers, require all the services we'll want,
+ // for feelers, only require they be a full node (only because most
+ // SPV clients don't have a good address DB available)
+ if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) {
+ continue;
+ } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {
continue;
}
@@ -1821,13 +1857,6 @@ void CConnman::ThreadOpenConnections()
continue;
addrConnect = addr;
-
- // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services
- if (nOutboundRelevant >= (nMaxOutbound >> 1)) {
- addrConnect.nServices = REQUIRED_SERVICES;
- } else {
- addrConnect.nServices = nRequiredServices;
- }
break;
}
@@ -1854,8 +1883,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
{
LOCK(cs_vAddedNodes);
ret.reserve(vAddedNodes.size());
- for (const std::string& strAddNode : vAddedNodes)
- lAddresses.push_back(strAddNode);
+ std::copy(vAddedNodes.cbegin(), vAddedNodes.cend(), std::back_inserter(lAddresses));
}
@@ -1901,11 +1929,6 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
void CConnman::ThreadOpenAddedConnections()
{
- {
- LOCK(cs_vAddedNodes);
- vAddedNodes = gArgs.GetArgs("-addnode");
- }
-
while (true)
{
CSemaphoreGrant grant(*semAddnode);
@@ -1918,11 +1941,9 @@ void CConnman::ThreadOpenAddedConnections()
// the addednodeinfo state might change.
break;
}
- // If strAddedNode is an IP/port, decode it immediately, so
- // OpenNetworkConnection can detect existing connections to that IP/port.
tried = true;
- CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort()));
- OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true);
+ CAddress addr(CService(), NODE_NONE);
+ OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), false, false, true);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return;
}
@@ -1934,7 +1955,7 @@ void CConnman::ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode)
+bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection)
{
//
// Initiate outbound network connection
@@ -1963,10 +1984,10 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;
- if (fAddnode)
- pnode->fAddnode = true;
+ if (manual_connection)
+ pnode->m_manual_connection = true;
- GetNodeSignals().InitializeNode(pnode, *this);
+ m_msgproc->InitializeNode(pnode);
{
LOCK(cs_vNodes);
vNodes.push_back(pnode);
@@ -1996,16 +2017,16 @@ void CConnman::ThreadMessageHandler()
continue;
// Receive messages
- bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc);
+ bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
if (flagInterruptMsgProc)
return;
-
// Send messages
{
LOCK(pnode->cs_sendProcessing);
- GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
+ m_msgproc->SendMessages(pnode, flagInterruptMsgProc);
}
+
if (flagInterruptMsgProc)
return;
}
@@ -2044,44 +2065,21 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
return false;
}
- SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
+ SOCKET hListenSocket = CreateSocket(addrBind);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
return false;
}
- if (!IsSelectableSocket(hListenSocket))
- {
- strError = "Error: Couldn't create a listenable socket for incoming connections";
- LogPrintf("%s\n", strError);
- return false;
- }
-
-
#ifndef WIN32
-#ifdef SO_NOSIGPIPE
- // Different way of disabling SIGPIPE on BSD
- setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
-#endif
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
- // Disable Nagle's algorithm
- setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int));
#else
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
- setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
#endif
- // Set to non-blocking, incoming connections will also inherit this
- if (!SetSocketNonBlocking(hListenSocket, true)) {
- CloseSocket(hListenSocket);
- strError = strprintf("BindListenPort: Setting listening socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
- LogPrintf("%s\n", strError);
- return false;
- }
-
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
@@ -2208,9 +2206,8 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
nLastNodeId = 0;
nSendBufferMaxSize = 0;
nReceiveFloodSize = 0;
- semOutbound = nullptr;
- semAddnode = nullptr;
flagInterruptMsgProc = false;
+ SetTryNewOutboundPeer(false);
Options connOptions;
Init(connOptions);
@@ -2256,10 +2253,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
{
Init(connOptions);
- nTotalBytesRecv = 0;
- nTotalBytesSent = 0;
- nMaxOutboundTotalBytesSentInCycle = 0;
- nMaxOutboundCycleStartTime = 0;
+ {
+ LOCK(cs_totalBytesRecv);
+ nTotalBytesRecv = 0;
+ }
+ {
+ LOCK(cs_totalBytesSent);
+ nTotalBytesSent = 0;
+ nMaxOutboundTotalBytesSentInCycle = 0;
+ nMaxOutboundCycleStartTime = 0;
+ }
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
if (clientInterface) {
@@ -2314,16 +2317,17 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (semOutbound == nullptr) {
// initialize semaphore
- semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
+ semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
}
if (semAddnode == nullptr) {
// initialize semaphore
- semAddnode = new CSemaphore(nMaxAddnode);
+ semAddnode = MakeUnique<CSemaphore>(nMaxAddnode);
}
//
// Start threads
//
+ assert(m_msgproc);
InterruptSocks5(false);
interruptNet.reset();
flagInterruptMsgProc = false;
@@ -2344,9 +2348,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
// Initiate outbound connections from -addnode
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
- // Initiate outbound connections unless connect=0
- if (!gArgs.IsArgSet("-connect") || gArgs.GetArgs("-connect").size() != 1 || gArgs.GetArgs("-connect")[0] != "0")
- threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));
+ if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
+ if (clientInterface) {
+ clientInterface->ThreadSafeMessageBox(
+ _("Cannot provide specific connections and have addrman find outgoing connections at the same."),
+ "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+ if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty())
+ threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this, connOptions.m_specified_outgoing)));
// Process messages
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
@@ -2433,19 +2444,18 @@ void CConnman::Stop()
vNodes.clear();
vNodesDisconnected.clear();
vhListenSocket.clear();
- delete semOutbound;
- semOutbound = nullptr;
- delete semAddnode;
- semAddnode = nullptr;
+ semOutbound.reset();
+ semAddnode.reset();
}
void CConnman::DeleteNode(CNode* pnode)
{
assert(pnode);
bool fUpdateConnectionTime = false;
- GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
- if(fUpdateConnectionTime)
+ m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
+ if(fUpdateConnectionTime) {
addrman.Connected(pnode->addr);
+ }
delete pnode;
}
@@ -2483,9 +2493,8 @@ std::vector<CAddress> CConnman::GetAddresses()
bool CConnman::AddNode(const std::string& strNode)
{
LOCK(cs_vAddedNodes);
- for(std::vector<std::string>::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
- if (strNode == *it)
- return false;
+ for (const std::string& it : vAddedNodes) {
+ if (strNode == it) return false;
}
vAddedNodes.push_back(strNode);
@@ -2511,9 +2520,11 @@ size_t CConnman::GetNodeCount(NumConnections flags)
return vNodes.size();
int nNum = 0;
- for(std::vector<CNode*>::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it)
- if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
+ for (const auto& pnode : vNodes) {
+ if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) {
nNum++;
+ }
+ }
return nNum;
}
@@ -2523,8 +2534,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
vstats.clear();
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
- for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) {
- CNode* pnode = *it;
+ for (CNode* pnode : vNodes) {
vstats.emplace_back();
pnode->copyStats(vstats.back());
}
@@ -2691,7 +2701,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nSendVersion(0)
{
nServices = NODE_NONE;
- nServicesExpected = NODE_NONE;
hSocket = hSocketIn;
nRecvVersion = INIT_PROTO_VERSION;
nLastSend = 0;
@@ -2704,7 +2713,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
strSubVer = "";
fWhitelisted = false;
fOneShot = false;
- fAddnode = false;
+ m_manual_connection = false;
fClient = false; // set by version message
fFeeler = false;
fSuccessfullyConnected = false;
@@ -2722,7 +2731,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nNextInvSend = 0;
fRelayTxes = false;
fSentAddr = false;
- pfilter = new CBloomFilter();
+ pfilter = MakeUnique<CBloomFilter>();
timeLastMempoolReq = 0;
nLastBlockTime = 0;
nLastTXTime = 0;
@@ -2752,9 +2761,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
CNode::~CNode()
{
CloseSocket(hSocket);
-
- if (pfilter)
- delete pfilter;
}
void CNode::AskFor(const CInv& inv)
diff --git a/src/net.h b/src/net.h
index a32736aa97..d0fd050970 100644
--- a/src/net.h
+++ b/src/net.h
@@ -6,21 +6,21 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
-#include "addrdb.h"
-#include "addrman.h"
-#include "amount.h"
-#include "bloom.h"
-#include "compat.h"
-#include "hash.h"
-#include "limitedmap.h"
-#include "netaddress.h"
-#include "policy/feerate.h"
-#include "protocol.h"
-#include "random.h"
-#include "streams.h"
-#include "sync.h"
-#include "uint256.h"
-#include "threadinterrupt.h"
+#include <addrdb.h>
+#include <addrman.h>
+#include <amount.h>
+#include <bloom.h>
+#include <compat.h>
+#include <hash.h>
+#include <limitedmap.h>
+#include <netaddress.h>
+#include <policy/feerate.h>
+#include <protocol.h>
+#include <random.h>
+#include <streams.h>
+#include <sync.h>
+#include <uint256.h>
+#include <threadinterrupt.h>
#include <atomic>
#include <deque>
@@ -33,7 +33,6 @@
#include <arpa/inet.h>
#endif
-#include <boost/signals2/signal.hpp>
class CScheduler;
class CNode;
@@ -85,8 +84,6 @@ static const bool DEFAULT_FORCEDNSSEED = false;
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
-static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
-
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
@@ -116,7 +113,7 @@ struct CSerializedNetMsg
std::string command;
};
-
+class NetEventsInterface;
class CConnman
{
public:
@@ -131,13 +128,13 @@ public:
struct Options
{
ServiceFlags nLocalServices = NODE_NONE;
- ServiceFlags nRelevantServices = NODE_NONE;
int nMaxConnections = 0;
int nMaxOutbound = 0;
int nMaxAddnode = 0;
int nMaxFeeler = 0;
int nBestHeight = 0;
CClientUIInterface* uiInterface = nullptr;
+ NetEventsInterface* m_msgproc = nullptr;
unsigned int nSendBufferMaxSize = 0;
unsigned int nReceiveFloodSize = 0;
uint64_t nMaxOutboundTimeframe = 0;
@@ -145,22 +142,32 @@ public:
std::vector<std::string> vSeedNodes;
std::vector<CSubNet> vWhitelistedRange;
std::vector<CService> vBinds, vWhiteBinds;
+ bool m_use_addrman_outgoing = true;
+ std::vector<std::string> m_specified_outgoing;
+ std::vector<std::string> m_added_nodes;
};
void Init(const Options& connOptions) {
nLocalServices = connOptions.nLocalServices;
- nRelevantServices = connOptions.nRelevantServices;
nMaxConnections = connOptions.nMaxConnections;
nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections);
nMaxAddnode = connOptions.nMaxAddnode;
nMaxFeeler = connOptions.nMaxFeeler;
nBestHeight = connOptions.nBestHeight;
clientInterface = connOptions.uiInterface;
+ m_msgproc = connOptions.m_msgproc;
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
nReceiveFloodSize = connOptions.nReceiveFloodSize;
- nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
- nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ {
+ LOCK(cs_totalBytesSent);
+ nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
+ nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ }
vWhitelistedRange = connOptions.vWhitelistedRange;
+ {
+ LOCK(cs_vAddedNodes);
+ vAddedNodes = connOptions.m_added_nodes;
+ }
}
CConnman(uint64_t seed0, uint64_t seed1);
@@ -170,7 +177,7 @@ public:
void Interrupt();
bool GetNetworkActive() const { return fNetworkActive; };
void SetNetworkActive(bool active);
- bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -250,6 +257,19 @@ public:
void GetBanned(banmap_t &banmap);
void SetBanned(const banmap_t &banmap);
+ // This allows temporarily exceeding nMaxOutbound, with the goal of finding
+ // a peer that is better than all our current peers.
+ void SetTryNewOutboundPeer(bool flag);
+ bool GetTryNewOutboundPeer();
+
+ // Return the number of outbound peers we have in excess of our target (eg,
+ // if we previously called SetTryNewOutboundPeer(true), and have since set
+ // to false, we may have extra peers that we wish to disconnect). This may
+ // return a value less than (num_outbound_connections - num_outbound_slots)
+ // in cases where some outbound connections are not yet fully connected, or
+ // not yet fully disconnected.
+ int GetExtraOutboundCount();
+
bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
@@ -308,7 +328,7 @@ private:
void ThreadOpenAddedConnections();
void AddOneShot(const std::string& strDest);
void ProcessOneShot();
- void ThreadOpenConnections();
+ void ThreadOpenConnections(std::vector<std::string> connect);
void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket);
void ThreadSocketHandler();
@@ -350,14 +370,14 @@ private:
// Network usage totals
CCriticalSection cs_totalBytesRecv;
CCriticalSection cs_totalBytesSent;
- uint64_t nTotalBytesRecv;
- uint64_t nTotalBytesSent;
+ uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv);
+ uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent);
// outbound limit & stats
- uint64_t nMaxOutboundTotalBytesSentInCycle;
- uint64_t nMaxOutboundCycleStartTime;
- uint64_t nMaxOutboundLimit;
- uint64_t nMaxOutboundTimeframe;
+ uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundTimeframe GUARDED_BY(cs_totalBytesSent);
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
@@ -375,7 +395,7 @@ private:
CAddrMan addrman;
std::deque<std::string> vOneShots;
CCriticalSection cs_vOneShots;
- std::vector<std::string> vAddedNodes;
+ std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
CCriticalSection cs_vAddedNodes;
std::vector<CNode*> vNodes;
std::list<CNode*> vNodesDisconnected;
@@ -385,17 +405,15 @@ private:
/** Services this instance offers */
ServiceFlags nLocalServices;
- /** Services this instance cares about */
- ServiceFlags nRelevantServices;
-
- CSemaphore *semOutbound;
- CSemaphore *semAddnode;
+ std::unique_ptr<CSemaphore> semOutbound;
+ std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections;
int nMaxOutbound;
int nMaxAddnode;
int nMaxFeeler;
std::atomic<int> nBestHeight;
CClientUIInterface* clientInterface;
+ NetEventsInterface* m_msgproc;
/** SipHasher seeds for deterministic randomness */
const uint64_t nSeed0, nSeed1;
@@ -414,6 +432,13 @@ private:
std::thread threadOpenAddedConnections;
std::thread threadOpenConnections;
std::thread threadMessageHandler;
+
+ /** flag for deciding to connect to an extra outbound peer,
+ * in excess of nMaxOutbound
+ * This takes the place of a feeler connection */
+ std::atomic_bool m_try_another_outbound_peer;
+
+ friend struct CConnmanTest;
};
extern std::unique_ptr<CConnman> g_connman;
void Discover(boost::thread_group& threadGroup);
@@ -436,19 +461,18 @@ struct CombinerAll
}
};
-// Signals for message handling
-struct CNodeSignals
+/**
+ * Interface for message handling
+ */
+class NetEventsInterface
{
- boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> SendMessages;
- boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode;
- boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
+public:
+ virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+ virtual bool SendMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+ virtual void InitializeNode(CNode* pnode) = 0;
+ virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0;
};
-
-CNodeSignals& GetNodeSignals();
-
-
enum
{
LOCAL_NONE, // unknown
@@ -508,7 +532,7 @@ public:
int nVersion;
std::string cleanSubVer;
bool fInbound;
- bool fAddnode;
+ bool m_manual_connection;
int nStartingHeight;
uint64_t nSendBytes;
mapMsgCmdSize mapSendBytesPerMsgCmd;
@@ -580,7 +604,6 @@ class CNode
public:
// socket
std::atomic<ServiceFlags> nServices;
- ServiceFlags nServicesExpected;
SOCKET hSocket;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
@@ -618,7 +641,7 @@ public:
bool fWhitelisted; // This peer can bypass DoS banning.
bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
- bool fAddnode;
+ bool m_manual_connection;
bool fClient;
const bool fInbound;
std::atomic_bool fSuccessfullyConnected;
@@ -631,7 +654,7 @@ public:
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
- CBloomFilter* pfilter;
+ std::unique_ptr<CBloomFilter> pfilter;
std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup;
@@ -699,13 +722,11 @@ public:
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
+ CNode(const CNode&) = delete;
+ CNode& operator=(const CNode&) = delete;
private:
- CNode(const CNode&);
- void operator=(const CNode&);
const NodeId id;
-
-
const uint64_t nLocalHostNonce;
// Services offered to this peer
const ServiceFlags nLocalServices;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index e09b56a631..20426eaceb 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3,33 +3,32 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "net_processing.h"
-
-#include "addrman.h"
-#include "arith_uint256.h"
-#include "blockencodings.h"
-#include "chainparams.h"
-#include "consensus/validation.h"
-#include "hash.h"
-#include "init.h"
-#include "validation.h"
-#include "merkleblock.h"
-#include "net.h"
-#include "netmessagemaker.h"
-#include "netbase.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "reverse_iterator.h"
-#include "tinyformat.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
+#include <net_processing.h>
+
+#include <addrman.h>
+#include <arith_uint256.h>
+#include <blockencodings.h>
+#include <chainparams.h>
+#include <consensus/validation.h>
+#include <hash.h>
+#include <init.h>
+#include <validation.h>
+#include <merkleblock.h>
+#include <netmessagemaker.h>
+#include <netbase.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <reverse_iterator.h>
+#include <scheduler.h>
+#include <tinyformat.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
@@ -40,7 +39,7 @@ std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of
struct IteratorComparator
{
template<typename I>
- bool operator()(const I& a, const I& b)
+ bool operator()(const I& a, const I& b) const
{
return &(*a) < &(*b);
}
@@ -61,6 +60,14 @@ static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUAR
static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8]
+/// Age after which a stale block will no longer be served if requested as
+/// protection against fingerprinting. Set to one month, denominated in seconds.
+static const int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60;
+
+/// Age after which a block is considered historical for purposes of rate
+/// limiting block relay. Set to one week, denominated in seconds.
+static const int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60;
+
// Internal stuff
namespace {
/** Number of nodes with fSyncStarted. */
@@ -116,6 +123,12 @@ namespace {
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0;
+ /** Number of outbound peers with m_chain_sync.m_protect. */
+ int g_outbound_peers_with_protect_from_disconnect = 0;
+
+ /** When our tip was last updated. */
+ int64_t g_last_tip_update = 0;
+
/** Relay map, protected by cs_main. */
typedef std::map<uint256, CTransactionRef> MapRelay;
MapRelay mapRelay;
@@ -123,11 +136,6 @@ namespace {
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;
} // namespace
-//////////////////////////////////////////////////////////////////////////////
-//
-// Registration of network node signals.
-//
-
namespace {
struct CBlockReject {
@@ -198,6 +206,36 @@ struct CNodeState {
*/
bool fSupportsDesiredCmpctVersion;
+ /** State used to enforce CHAIN_SYNC_TIMEOUT
+ * Only in effect for outbound, non-manual connections, with
+ * m_protect == false
+ * Algorithm: if a peer's best known block has less work than our tip,
+ * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future:
+ * - If at timeout their best known block now has more work than our tip
+ * when the timeout was set, then either reset the timeout or clear it
+ * (after comparing against our current tip's work)
+ * - If at timeout their best known block still has less work than our
+ * tip did when the timeout was set, then send a getheaders message,
+ * and set a shorter timeout, HEADERS_RESPONSE_TIME seconds in future.
+ * If their best known block is still behind when that new timeout is
+ * reached, disconnect.
+ */
+ struct ChainSyncTimeoutState {
+ //! A timeout used for checking whether our peer has sufficiently synced
+ int64_t m_timeout;
+ //! A header with the work we require on our peer's chain
+ const CBlockIndex * m_work_header;
+ //! After timeout is reached, set to true after sending getheaders
+ bool m_sent_getheaders;
+ //! Whether this peer is protected from disconnection due to a bad/slow chain
+ bool m_protect;
+ };
+
+ ChainSyncTimeoutState m_chain_sync;
+
+ //! Time of last new block announcement
+ int64_t m_last_block_announcement;
+
CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
fCurrentlyConnected = false;
nMisbehavior = 0;
@@ -220,6 +258,8 @@ struct CNodeState {
fHaveWitness = false;
fWantsCmpctWitness = false;
fSupportsDesiredCmpctVersion = false;
+ m_chain_sync = { 0, nullptr, false, false };
+ m_last_block_announcement = 0;
}
};
@@ -244,7 +284,7 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload;
}
-void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
+void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
{
ServiceFlags nLocalNodeServices = pnode->GetLocalServices();
uint64_t nonce = pnode->GetLocalNonce();
@@ -255,7 +295,7 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
- connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
+ connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
if (fLogIPs) {
@@ -265,49 +305,6 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
}
}
-void InitializeNode(CNode *pnode, CConnman& connman) {
- CAddress addr = pnode->addr;
- std::string addrName = pnode->GetAddrName();
- NodeId nodeid = pnode->GetId();
- {
- LOCK(cs_main);
- mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
- }
- if(!pnode->fInbound)
- PushNodeVersion(pnode, connman, GetTime());
-}
-
-void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
- fUpdateConnectionTime = false;
- LOCK(cs_main);
- CNodeState *state = State(nodeid);
-
- if (state->fSyncStarted)
- nSyncStarted--;
-
- if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
- fUpdateConnectionTime = true;
- }
-
- for (const QueuedBlock& entry : state->vBlocksInFlight) {
- mapBlocksInFlight.erase(entry.hash);
- }
- EraseOrphansFor(nodeid);
- nPreferredDownload -= state->fPreferredDownload;
- nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
- assert(nPeersWithValidatedDownloads >= 0);
-
- mapNodeState.erase(nodeid);
-
- if (mapNodeState.empty()) {
- // Do a consistency check after the last peer is removed.
- assert(mapBlocksInFlight.empty());
- assert(nPreferredDownload == 0);
- assert(nPeersWithValidatedDownloads == 0);
- }
- LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
-}
-
// Requires cs_main.
// Returns a bool indicating whether we requested this block.
// Also used if a block was /not/ received and timed out or started with another peer
@@ -315,6 +312,7 @@ bool MarkBlockAsReceived(const uint256& hash) {
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
+ assert(state != nullptr);
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
// Last validated block on the queue was received.
@@ -402,7 +400,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
}
}
-void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) {
+void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) {
AssertLockHeld(cs_main);
CNodeState* nodestate = State(nodeid);
if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) {
@@ -417,26 +415,33 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) {
return;
}
}
- connman.ForNode(nodeid, [&connman](CNode* pfrom){
- bool fAnnounceUsingCMPCTBLOCK = false;
+ connman->ForNode(nodeid, [connman](CNode* pfrom){
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
- connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, nCMPCTBLOCKVersion](CNode* pnodeStop){
+ connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion));
return true;
});
lNodesAnnouncingHeaderAndIDs.pop_front();
}
- fAnnounceUsingCMPCTBLOCK = true;
- connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion));
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
return true;
});
}
}
+bool TipMayBeStale(const Consensus::Params &consensusParams)
+{
+ AssertLockHeld(cs_main);
+ if (g_last_tip_update == 0) {
+ g_last_tip_update = GetTime();
+ }
+ return g_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
+}
+
// Requires cs_main
bool CanDirectFetch(const Consensus::Params &consensusParams)
{
@@ -466,7 +471,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
return;
}
@@ -543,6 +548,69 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
} // namespace
+// This function is used for testing the stale tip eviction logic, see
+// DoS_tests.cpp
+void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
+{
+ LOCK(cs_main);
+ CNodeState *state = State(node);
+ if (state) state->m_last_block_announcement = time_in_seconds;
+}
+
+// Returns true for outbound peers, excluding manual connections, feelers, and
+// one-shots
+bool IsOutboundDisconnectionCandidate(const CNode *node)
+{
+ return !(node->fInbound || node->m_manual_connection || node->fFeeler || node->fOneShot);
+}
+
+void PeerLogicValidation::InitializeNode(CNode *pnode) {
+ CAddress addr = pnode->addr;
+ std::string addrName = pnode->GetAddrName();
+ NodeId nodeid = pnode->GetId();
+ {
+ LOCK(cs_main);
+ mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
+ }
+ if(!pnode->fInbound)
+ PushNodeVersion(pnode, connman, GetTime());
+}
+
+void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
+ fUpdateConnectionTime = false;
+ LOCK(cs_main);
+ CNodeState *state = State(nodeid);
+ assert(state != nullptr);
+
+ if (state->fSyncStarted)
+ nSyncStarted--;
+
+ if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
+ fUpdateConnectionTime = true;
+ }
+
+ for (const QueuedBlock& entry : state->vBlocksInFlight) {
+ mapBlocksInFlight.erase(entry.hash);
+ }
+ EraseOrphansFor(nodeid);
+ nPreferredDownload -= state->fPreferredDownload;
+ nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
+ assert(nPeersWithValidatedDownloads >= 0);
+ g_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
+ assert(g_outbound_peers_with_protect_from_disconnect >= 0);
+
+ mapNodeState.erase(nodeid);
+
+ if (mapNodeState.empty()) {
+ // Do a consistency check after the last peer is removed.
+ assert(mapBlocksInFlight.empty());
+ assert(nPreferredDownload == 0);
+ assert(nPeersWithValidatedDownloads == 0);
+ assert(g_outbound_peers_with_protect_from_disconnect == 0);
+ }
+ LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
+}
+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
@@ -558,28 +626,12 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
return true;
}
-void RegisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.ProcessMessages.connect(&ProcessMessages);
- nodeSignals.SendMessages.connect(&SendMessages);
- nodeSignals.InitializeNode.connect(&InitializeNode);
- nodeSignals.FinalizeNode.connect(&FinalizeNode);
-}
-
-void UnregisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
- nodeSignals.SendMessages.disconnect(&SendMessages);
- nodeSignals.InitializeNode.disconnect(&InitializeNode);
- nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
-}
-
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
-void AddToCompactExtraTransactions(const CTransactionRef& tx)
+void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);
if (max_extra_txn <= 0)
@@ -725,9 +777,30 @@ void Misbehaving(NodeId pnode, int howmuch)
// blockchain -> download logic notification
//
-PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {
+// To prevent fingerprinting attacks, only send blocks/headers outside of the
+// active chain if they are no more than a month older (both in time, and in
+// best equivalent proof of work) than the best header chain we know about and
+// we fully-validated them at some point.
+static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+{
+ AssertLockHeld(cs_main);
+ if (chainActive.Contains(pindex)) return true;
+ return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
+ (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
+ (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
+}
+
+PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler) : connman(connmanIn), m_stale_tip_check_time(0) {
// Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ // Stale tip checking and peer eviction are on two different timers, but we
+ // don't want them to get out of sync due to drift in the scheduler, so we
+ // combine them in one function and schedule at the quicker (peer-eviction)
+ // timer.
+ static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer");
+ scheduler.scheduleEvery(std::bind(&PeerLogicValidation::CheckForStaleTipAndEvictPeers, this, consensusParams), EXTRA_PEER_CHECK_INTERVAL * 1000);
}
void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) {
@@ -758,6 +831,8 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb
}
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
+
+ g_last_tip_update = GetTime();
}
// All of the following cache a recent block, and are protected by cs_most_recent_block
@@ -865,7 +940,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
!IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
- MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman);
+ MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
}
}
if (it != mapBlockSource.end())
@@ -910,16 +985,16 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true;
}
-static void RelayTransaction(const CTransaction& tx, CConnman& connman)
+static void RelayTransaction(const CTransaction& tx, CConnman* connman)
{
CInv inv(MSG_TX, tx.GetHash());
- connman.ForEachNode([&inv](CNode* pnode)
+ connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
}
-static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
+static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman)
{
unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
@@ -927,7 +1002,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
+ const CSipHasher hasher = connman->GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
FastRandomContext insecure_rand;
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
@@ -952,10 +1027,10 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
}
};
- connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+ connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
std::vector<CInv> vNotFound;
@@ -999,25 +1074,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
CValidationState dummy;
ActivateBestChain(dummy, Params(), a_recent_block);
}
- if (chainActive.Contains(mi->second)) {
- send = true;
- } else {
- static const int nOneMonth = 30 * 24 * 60 * 60;
- // To prevent fingerprinting attacks, only send blocks outside of the active
- // chain if they are valid, and no more than a month older (both in time, and in
- // best equivalent proof of work) than the best header chain we know about.
- send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
- (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&
- (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth);
- if (!send) {
- LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
- }
+ send = BlockRequestAllowed(mi->second, consensusParams);
+ if (!send) {
+ LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
}
}
// disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes
- static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
- if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
+ if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
{
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@@ -1025,6 +1089,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->fDisconnect = true;
send = false;
}
+ // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
+ if (send && !pfrom->fWhitelisted && (
+ (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ )) {
+ LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
+
+ //disconnect node and prevent it from stalling (would otherwise wait for the missing block)
+ pfrom->fDisconnect = true;
+ send = false;
+ }
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
@@ -1040,9 +1114,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pblock = pblockRead;
}
if (inv.type == MSG_BLOCK)
- connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
+ connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_WITNESS_BLOCK)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_FILTERED_BLOCK)
{
bool sendMerkleBlock = false;
@@ -1055,7 +1129,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
if (sendMerkleBlock) {
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -1064,7 +1138,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
for (PairType& pair : merkleBlock.vMatchedTxn)
- connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
+ connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
}
// else
// no response
@@ -1079,13 +1153,13 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else {
CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
} else {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
}
}
@@ -1097,7 +1171,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// wait for other stuff first.
std::vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
pfrom->hashContinue.SetNull();
}
}
@@ -1109,14 +1183,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
auto mi = mapRelay.find(inv.hash);
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
if (mi != mapRelay.end()) {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
push = true;
} else if (pfrom->timeLastMempoolReq) {
auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
push = true;
}
}
@@ -1143,7 +1217,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
}
}
@@ -1155,7 +1229,7 @@ uint32_t GetFetchFlags(CNode* pfrom) {
return nFetchFlags;
}
-inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) {
+inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman* connman) {
BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) {
@@ -1169,10 +1243,229 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
LOCK(cs_main);
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
+}
+
+bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool punish_duplicate_invalid)
+{
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ size_t nCount = headers.size();
+
+ if (nCount == 0) {
+ // Nothing interesting. Stop asking this peers for more headers.
+ return true;
+ }
+
+ bool received_new_header = false;
+ const CBlockIndex *pindexLast = nullptr;
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ // If this looks like it could be a block announcement (nCount <
+ // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
+ // don't connect:
+ // - Send a getheaders message in response to try to connect the chain.
+ // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
+ // don't connect before giving DoS points
+ // - Once a headers message is received that is valid and does connect,
+ // nUnconnectingHeaders gets reset back to 0.
+ if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
+ nodestate->nUnconnectingHeaders++;
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
+ headers[0].GetHash().ToString(),
+ headers[0].hashPrevBlock.ToString(),
+ pindexBestHeader->nHeight,
+ pfrom->GetId(), nodestate->nUnconnectingHeaders);
+ // Set hashLastUnknownBlock for this peer, so that if we
+ // eventually get the headers - even from a different peer -
+ // we can use this peer to download.
+ UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
+
+ if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
+ Misbehaving(pfrom->GetId(), 20);
+ }
+ return true;
+ }
+
+ uint256 hashLastBlock;
+ for (const CBlockHeader& header : headers) {
+ if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
+ Misbehaving(pfrom->GetId(), 20);
+ return error("non-continuous headers sequence");
+ }
+ hashLastBlock = header.GetHash();
+ }
+
+ // If we don't have the last header, then they'll have given us
+ // something new (if these headers are valid).
+ if (mapBlockIndex.find(hashLastBlock) == mapBlockIndex.end()) {
+ received_new_header = true;
+ }
+ }
+
+ CValidationState state;
+ CBlockHeader first_invalid_header;
+ if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ LOCK(cs_main);
+ if (nDoS > 0) {
+ Misbehaving(pfrom->GetId(), nDoS);
+ }
+ if (punish_duplicate_invalid && mapBlockIndex.find(first_invalid_header.GetHash()) != mapBlockIndex.end()) {
+ // Goal: don't allow outbound peers to use up our outbound
+ // connection slots if they are on incompatible chains.
+ //
+ // We ask the caller to set punish_invalid appropriately based
+ // on the peer and the method of header delivery (compact
+ // blocks are allowed to be invalid in some circumstances,
+ // under BIP 152).
+ // Here, we try to detect the narrow situation that we have a
+ // valid block header (ie it was valid at the time the header
+ // was received, and hence stored in mapBlockIndex) but know the
+ // block is invalid, and that a peer has announced that same
+ // block as being on its active chain.
+ // Disconnect the peer in such a situation.
+ //
+ // Note: if the header that is invalid was not accepted to our
+ // mapBlockIndex at all, that may also be grounds for
+ // disconnecting the peer, as the chain they are on is likely
+ // to be incompatible. However, there is a circumstance where
+ // that does not hold: if the header's timestamp is more than
+ // 2 hours ahead of our current time. In that case, the header
+ // may become valid in the future, and we don't want to
+ // disconnect a peer merely for serving us one too-far-ahead
+ // block header, to prevent an attacker from splitting the
+ // network by mining a block right at the 2 hour boundary.
+ //
+ // TODO: update the DoS logic (or, rather, rewrite the
+ // DoS-interface between validation and net_processing) so that
+ // the interface is cleaner, and so that we disconnect on all the
+ // reasons that a peer's headers chain is incompatible
+ // with ours (eg block->nVersion softforks, MTP violations,
+ // etc), and not just the duplicate-invalid case.
+ pfrom->fDisconnect = true;
+ }
+ return error("invalid header received");
+ }
+ }
+
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+ if (nodestate->nUnconnectingHeaders > 0) {
+ LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
+ }
+ nodestate->nUnconnectingHeaders = 0;
+
+ assert(pindexLast);
+ UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
+
+ // From here, pindexBestKnownBlock should be guaranteed to be non-null,
+ // because it is set in UpdateBlockAvailability. Some nullptr checks
+ // are still present, however, as belt-and-suspenders.
+
+ if (received_new_header && pindexLast->nChainWork > chainActive.Tip()->nChainWork) {
+ nodestate->m_last_block_announcement = GetTime();
+ }
+
+ if (nCount == MAX_HEADERS_RESULTS) {
+ // Headers message had its maximum size; the peer may have more headers.
+ // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
+ // from there instead.
+ LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
+ }
+
+ bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
+ // If this set of headers is valid and ends in a block with at least as
+ // much work as our tip, download as much as possible.
+ if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
+ std::vector<const CBlockIndex*> vToFetch;
+ const CBlockIndex *pindexWalk = pindexLast;
+ // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
+ while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
+ !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
+ (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
+ // We don't have this block, and it's not yet in flight.
+ vToFetch.push_back(pindexWalk);
+ }
+ pindexWalk = pindexWalk->pprev;
+ }
+ // If pindexWalk still isn't on our main chain, we're looking at a
+ // very large reorg at a time we think we're close to caught up to
+ // the main chain -- this shouldn't really happen. Bail out on the
+ // direct fetch and rely on parallel download instead.
+ if (!chainActive.Contains(pindexWalk)) {
+ LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
+ pindexLast->GetBlockHash().ToString(),
+ pindexLast->nHeight);
+ } else {
+ std::vector<CInv> vGetData;
+ // Download as much as possible, from earliest to latest.
+ for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
+ if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ // Can't download any more from this peer
+ break;
+ }
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex);
+ LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
+ pindex->GetBlockHash().ToString(), pfrom->GetId());
+ }
+ if (vGetData.size() > 1) {
+ LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
+ pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
+ }
+ if (vGetData.size() > 0) {
+ if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
+ // In any case, we want to download using a compact block, not a regular one
+ vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
+ }
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ }
+ }
+ }
+ // If we're in IBD, we want outbound peers that will serve us a useful
+ // chain. Disconnect peers that are on chains with insufficient work.
+ if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
+ // When nCount < MAX_HEADERS_RESULTS, we know we have no more
+ // headers to fetch from this peer.
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ // This peer has too little work on their headers chain to help
+ // us sync -- disconnect if using an outbound slot (unless
+ // whitelisted or addnode).
+ // Note: We compare their tip to nMinimumChainWork (rather than
+ // chainActive.Tip()) because we won't start block download
+ // until we have a headers chain that has at least
+ // nMinimumChainWork, even if a peer has a chain past our tip,
+ // as an anti-DoS measure.
+ if (IsOutboundDisconnectionCandidate(pfrom)) {
+ LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ }
+ }
+ }
+
+ if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) {
+ // If this is an outbound peer, check to see if we should protect
+ // it from the bad/lagging chain logic.
+ if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
+ LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId());
+ nodestate->m_chain_sync.m_protect = true;
+ ++g_outbound_peers_with_protect_from_disconnect;
+ }
+ }
+ }
+
+ return true;
}
-bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
@@ -1225,7 +1518,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")));
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")));
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
@@ -1249,13 +1542,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound)
{
- connman.SetServices(pfrom->addr, nServices);
+ connman->SetServices(pfrom->addr, nServices);
}
- if (pfrom->nServicesExpected & ~nServices)
+ if (!pfrom->fInbound && !pfrom->fFeeler && !pfrom->m_manual_connection && !HasAllDesirableServiceFlags(nServices))
{
- LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, pfrom->nServicesExpected);
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
- strprintf("Expected to offer services %08x", pfrom->nServicesExpected)));
+ LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices));
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
+ strprintf("Expected to offer services %08x", GetDesirableServiceFlags(nServices))));
pfrom->fDisconnect = true;
return false;
}
@@ -1274,8 +1567,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from peers older than this proto version
- LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
+ LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
pfrom->fDisconnect = true;
return false;
@@ -1295,7 +1588,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!vRecv.empty())
vRecv >> fRelay;
// Disconnect if we connected to ourself
- if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
+ if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce))
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
@@ -1311,7 +1604,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (pfrom->fInbound)
PushNodeVersion(pfrom, connman, GetAdjustedTime());
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
pfrom->nServices = nServices;
pfrom->SetAddrLocal(addrMe);
@@ -1362,19 +1655,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
// Get recent addresses
- if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
+ if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000)
{
- connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
+ connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
pfrom->fGetAddr = true;
}
- connman.MarkAddressGood(pfrom->addr);
+ connman->MarkAddressGood(pfrom->addr);
}
std::string remoteAddr;
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
- LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
+ LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
cleanSubVer, pfrom->nVersion,
pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(),
remoteAddr);
@@ -1386,7 +1679,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// If the peer is old enough to have the old alert system, send it the final alert.
if (pfrom->nVersion <= 70012) {
CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION);
- connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
+ connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
}
// Feeler connections exist only to verify if address is online.
@@ -1417,6 +1710,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main);
State(pfrom->GetId())->fCurrentlyConnected = true;
+ LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s\n",
+ pfrom->nVersion.load(), pfrom->nStartingHeight, pfrom->GetId(),
+ (fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) : ""));
}
if (pfrom->nVersion >= SENDHEADERS_VERSION) {
@@ -1424,7 +1720,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
}
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
@@ -1435,9 +1731,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom->GetLocalServices() & NODE_WITNESS)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
nCMPCTBLOCKVersion = 1;
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
pfrom->fSuccessfullyConnected = true;
}
@@ -1456,7 +1752,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
+ if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000)
return true;
if (vAddr.size() > 1000)
{
@@ -1474,7 +1770,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (interruptMsgProc)
return true;
- if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
+ // We only bother storing full nodes, though this may include
+ // things which we would not make an outbound connection to, in
+ // part because we may make feeler connections to them.
+ if (!MayHaveUsefulAddressDB(addr.nServices))
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
@@ -1490,7 +1789,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (fReachable)
vAddrOk.push_back(addr);
}
- connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
+ connman->AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
@@ -1568,7 +1867,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// fell back to inv we probably have a reorg which we should get the headers for first,
// we now only provide a getheaders response here. When we receive the headers, we will
// then ask for the blocks we need.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
}
}
@@ -1692,7 +1991,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) {
- LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
+ LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
return true;
}
@@ -1742,6 +2041,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (mi == mapBlockIndex.end())
return true;
pindex = (*mi).second;
+
+ if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
+ LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId());
+ return true;
+ }
}
else
{
@@ -1774,7 +2078,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
}
@@ -1807,8 +2111,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
std::list<CTransactionRef> lRemovedTxn;
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs, &lRemovedTxn)) {
- mempool.check(pcoinsTip);
+ if (!AlreadyHave(inv) &&
+ AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ mempool.check(pcoinsTip.get());
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
@@ -1845,7 +2150,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (setMisbehaving.count(fromPeer))
continue;
- if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2, &lRemovedTxn)) {
+ if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx, connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
@@ -1875,7 +2180,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
recentRejects->insert(orphanHash);
}
}
- mempool.check(pcoinsTip);
+ mempool.check(pcoinsTip.get());
}
}
@@ -1955,7 +2260,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->GetId(),
FormatStateMessage(state));
if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));
if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
@@ -1969,15 +2274,21 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
+ bool received_new_header = false;
+
{
LOCK(cs_main);
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!IsInitialBlockDownload())
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
return true;
}
+
+ if (mapBlockIndex.find(cmpctblock.header.GetHash()) == mapBlockIndex.end()) {
+ received_new_header = true;
+ }
}
const CBlockIndex *pindex = nullptr;
@@ -1986,10 +2297,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
int nDoS;
if (state.IsInvalid(nDoS)) {
if (nDoS > 0) {
+ LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS);
+ } else {
+ LogPrint(BCLog::NET, "Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
}
- LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
return true;
}
}
@@ -2004,7 +2317,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// If we end up treating this as a plain headers message, call that as well
// without cs_main.
bool fRevertToHeaderProcessing = false;
- CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
// Keep a CBlock for "optimistic" compactblock reconstructions (see
// below)
@@ -2017,6 +2329,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
assert(pindex);
UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash());
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ // If this was a new header with more work than our tip, update the
+ // peer's last block announcement time
+ if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) {
+ nodestate->m_last_block_announcement = GetTime();
+ }
+
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
@@ -2030,7 +2350,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
return true;
}
@@ -2039,8 +2359,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
return true;
- CNodeState *nodestate = State(pfrom->GetId());
-
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
// Don't bother trying to process compact blocks from v1 peers
// after segwit activates.
@@ -2074,7 +2392,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
}
@@ -2091,7 +2409,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
fProcessBLOCKTXN = true;
} else {
req.blockhash = pindex->GetBlockHash();
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
}
} else {
// This block is either already in flight from a different
@@ -2117,14 +2435,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
- // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)
- std::vector<CBlock> headers;
- headers.push_back(cmpctblock.header);
- vHeadersMsg << headers;
fRevertToHeaderProcessing = true;
}
}
@@ -2133,8 +2447,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (fProcessBLOCKTXN)
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
- if (fRevertToHeaderProcessing)
- return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
+ if (fRevertToHeaderProcessing) {
+ // Headers received from HB compact block peers are permitted to be
+ // relayed before full validation (see BIP 152), so we don't want to disconnect
+ // the peer if the header turns out to be for an invalid block.
+ // Note that if a peer tries to build on an invalid chain, that
+ // will be detected and the peer will be banned.
+ return ProcessHeadersMessage(pfrom, connman, {cmpctblock.header}, chainparams, /*punish_duplicate_invalid=*/false);
+ }
if (fBlockReconstructed) {
// If we got here, we were able to optimistically reconstruct a
@@ -2144,7 +2464,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false));
}
bool fNewBlock = false;
- ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ // Setting fForceProcessing to true means that we bypass some of
+ // our anti-DoS protections in AcceptBlock, which filters
+ // unrequested blocks that might be trying to waste our resources
+ // (eg disk space). Because we only try to reconstruct blocks when
+ // we're close to caught up (via the CanDirectFetch() requirement
+ // above, combined with the behavior of not requesting blocks until
+ // we have a chain with at least nMinimumChainWork), and we ignore
+ // compact blocks with less work than our tip, it is safe to treat
+ // reconstructed compact blocks as having been requested.
+ ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
} else {
@@ -2191,7 +2520,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
} else {
// Block is either okay, or possibly we received
// READ_STATUS_CHECKBLOCK_FAILED.
@@ -2224,7 +2553,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool fNewBlock = false;
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
- ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
+ // disk-space attacks), but this should be safe due to the
+ // protections in the compact block handler -- see related comment
+ // in compact block optimistic reconstruction handling.
+ ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
} else {
@@ -2252,136 +2585,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- if (nCount == 0) {
- // Nothing interesting. Stop asking this peers for more headers.
- return true;
- }
-
- const CBlockIndex *pindexLast = nullptr;
- {
- LOCK(cs_main);
- CNodeState *nodestate = State(pfrom->GetId());
-
- // If this looks like it could be a block announcement (nCount <
- // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
- // don't connect:
- // - Send a getheaders message in response to try to connect the chain.
- // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
- // don't connect before giving DoS points
- // - Once a headers message is received that is valid and does connect,
- // nUnconnectingHeaders gets reset back to 0.
- if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
- nodestate->nUnconnectingHeaders++;
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
- LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
- headers[0].GetHash().ToString(),
- headers[0].hashPrevBlock.ToString(),
- pindexBestHeader->nHeight,
- pfrom->GetId(), nodestate->nUnconnectingHeaders);
- // Set hashLastUnknownBlock for this peer, so that if we
- // eventually get the headers - even from a different peer -
- // we can use this peer to download.
- UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
-
- if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
- Misbehaving(pfrom->GetId(), 20);
- }
- return true;
- }
-
- uint256 hashLastBlock;
- for (const CBlockHeader& header : headers) {
- if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
- Misbehaving(pfrom->GetId(), 20);
- return error("non-continuous headers sequence");
- }
- hashLastBlock = header.GetHash();
- }
- }
-
- CValidationState state;
- if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- if (nDoS > 0) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), nDoS);
- }
- return error("invalid header received");
- }
- }
-
- {
- LOCK(cs_main);
- CNodeState *nodestate = State(pfrom->GetId());
- if (nodestate->nUnconnectingHeaders > 0) {
- LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
- }
- nodestate->nUnconnectingHeaders = 0;
-
- assert(pindexLast);
- UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
-
- if (nCount == MAX_HEADERS_RESULTS) {
- // Headers message had its maximum size; the peer may have more headers.
- // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
- // from there instead.
- LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
- }
-
- bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
- // If this set of headers is valid and ends in a block with at least as
- // much work as our tip, download as much as possible.
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
- std::vector<const CBlockIndex*> vToFetch;
- const CBlockIndex *pindexWalk = pindexLast;
- // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
- while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
- !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
- (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
- // We don't have this block, and it's not yet in flight.
- vToFetch.push_back(pindexWalk);
- }
- pindexWalk = pindexWalk->pprev;
- }
- // If pindexWalk still isn't on our main chain, we're looking at a
- // very large reorg at a time we think we're close to caught up to
- // the main chain -- this shouldn't really happen. Bail out on the
- // direct fetch and rely on parallel download instead.
- if (!chainActive.Contains(pindexWalk)) {
- LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
- pindexLast->GetBlockHash().ToString(),
- pindexLast->nHeight);
- } else {
- std::vector<CInv> vGetData;
- // Download as much as possible, from earliest to latest.
- for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
- if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- // Can't download any more from this peer
- break;
- }
- uint32_t nFetchFlags = GetFetchFlags(pfrom);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex);
- LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
- pindex->GetBlockHash().ToString(), pfrom->GetId());
- }
- if (vGetData.size() > 1) {
- LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
- pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
- }
- if (vGetData.size() > 0) {
- if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
- // In any case, we want to download using a compact block, not a regular one
- vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
- }
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
- }
- }
- }
- }
+ // Headers received via a HEADERS message should be valid, and reflect
+ // the chain the peer is on. If we receive a known-invalid header,
+ // disconnect the peer if it is using one of our outbound connection
+ // slots.
+ bool should_punish = !pfrom->fInbound && !pfrom->m_manual_connection;
+ return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
}
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
@@ -2391,11 +2600,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->GetId());
- // Process all blocks from whitelisted peers, even if not requested,
- // unless we're still syncing with the network.
- // Such an unrequested block may still be processed, subject to the
- // conditions in AcceptBlock().
- bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ bool forceProcessing = false;
const uint256 hash(pblock->GetHash());
{
LOCK(cs_main);
@@ -2438,7 +2643,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->fSentAddr = true;
pfrom->vAddrToSend.clear();
- std::vector<CAddress> vAddr = connman.GetAddresses();
+ std::vector<CAddress> vAddr = connman->GetAddresses();
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr)
pfrom->PushAddress(addr, insecure_rand);
@@ -2454,7 +2659,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted)
{
LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
@@ -2483,7 +2688,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
}
@@ -2559,8 +2764,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else
{
LOCK(pfrom->cs_filter);
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter(filter);
+ pfrom->pfilter.reset(new CBloomFilter(filter));
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
@@ -2596,8 +2800,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{
LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter();
+ pfrom->pfilter.reset(new CBloomFilter());
}
pfrom->fRelayTxes = true;
}
@@ -2629,13 +2832,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
-static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)
+static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman)
{
AssertLockHeld(cs_main);
CNodeState &state = *State(pnode->GetId());
for (const CBlockReject& reject : state.rejects) {
- connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
+ connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
}
state.rejects.clear();
@@ -2643,15 +2846,15 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)
state.fShouldBan = false;
if (pnode->fWhitelisted)
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
- else if (pnode->fAddnode)
- LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString());
+ else if (pnode->m_manual_connection)
+ LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString());
else {
pnode->fDisconnect = true;
if (pnode->addr.IsLocal())
LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString());
else
{
- connman.Ban(pnode->addr, BanReasonNodeMisbehaving);
+ connman->Ban(pnode->addr, BanReasonNodeMisbehaving);
}
}
return true;
@@ -2659,7 +2862,7 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)
return false;
}
-bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
{
const CChainParams& chainparams = Params();
//
@@ -2693,7 +2896,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
// Just take one message
msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;
- pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize();
+ pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman->GetReceiveFloodSize();
fMoreWork = !pfrom->vProcessMsg.empty();
}
CNetMessage& msg(msgs.front());
@@ -2701,7 +2904,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
msg.SetVersion(pfrom->GetRecvVersion());
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());
+ LogPrint(BCLog::NET, "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());
pfrom->fDisconnect = true;
return false;
}
@@ -2710,7 +2913,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid(chainparams.MessageStart()))
{
- LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->GetId());
+ LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->GetId());
return fMoreWork;
}
std::string strCommand = hdr.GetCommand();
@@ -2723,7 +2926,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
const uint256& hash = msg.GetMessageHash();
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
{
- LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
SanitizeString(strCommand), nMessageSize,
HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
@@ -2742,21 +2945,21 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
}
catch (const std::ios_base::failure& e)
{
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else if (strstr(e.what(), "size too large"))
{
// Allow exceptions from over-long size
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
{
// Allow exceptions from non-canonical encoding
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
else
{
@@ -2770,7 +2973,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
}
if (!fRet) {
- LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
}
LOCK(cs_main);
@@ -2779,11 +2982,141 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
return fMoreWork;
}
+void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds)
+{
+ AssertLockHeld(cs_main);
+
+ CNodeState &state = *State(pto->GetId());
+ const CNetMsgMaker msgMaker(pto->GetSendVersion());
+
+ if (!state.m_chain_sync.m_protect && IsOutboundDisconnectionCandidate(pto) && state.fSyncStarted) {
+ // This is an outbound peer subject to disconnection if they don't
+ // announce a block with as much work as the current tip within
+ // CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if
+ // their chain has more work than ours, we should sync to it,
+ // unless it's invalid, in which case we should find that out and
+ // disconnect from them elsewhere).
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork) {
+ if (state.m_chain_sync.m_timeout != 0) {
+ state.m_chain_sync.m_timeout = 0;
+ state.m_chain_sync.m_work_header = nullptr;
+ state.m_chain_sync.m_sent_getheaders = false;
+ }
+ } else if (state.m_chain_sync.m_timeout == 0 || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) {
+ // Our best block known by this peer is behind our tip, and we're either noticing
+ // that for the first time, OR this peer was able to catch up to some earlier point
+ // where we checked against our tip.
+ // Either way, set a new timeout based on current tip.
+ state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT;
+ state.m_chain_sync.m_work_header = chainActive.Tip();
+ state.m_chain_sync.m_sent_getheaders = false;
+ } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) {
+ // No evidence yet that our peer has synced to a chain with work equal to that
+ // of our tip, when we first detected it was behind. Send a single getheaders
+ // message to give the peer a chance to update us.
+ if (state.m_chain_sync.m_sent_getheaders) {
+ // They've run out of time to catch up!
+ LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>");
+ pto->fDisconnect = true;
+ } else {
+ assert(state.m_chain_sync.m_work_header);
+ LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
+ state.m_chain_sync.m_sent_getheaders = true;
+ constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
+ // Bump the timeout to allow a response, which could clear the timeout
+ // (if the response shows the peer has synced), reset the timeout (if
+ // the peer syncs to the required work but not to our tip), or result
+ // in disconnect (if we advance to the timeout and pindexBestKnownBlock
+ // has not sufficiently progressed)
+ state.m_chain_sync.m_timeout = time_in_seconds + HEADERS_RESPONSE_TIME;
+ }
+ }
+ }
+}
+
+void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
+{
+ // Check whether we have too many outbound peers
+ int extra_peers = connman->GetExtraOutboundCount();
+ if (extra_peers > 0) {
+ // If we have more outbound peers than we target, disconnect one.
+ // Pick the outbound peer that least recently announced
+ // us a new block, with ties broken by choosing the more recent
+ // connection (higher node id)
+ NodeId worst_peer = -1;
+ int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
+
+ LOCK(cs_main);
+
+ connman->ForEachNode([&](CNode* pnode) {
+ // Ignore non-outbound peers, or nodes marked for disconnect already
+ if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) return;
+ CNodeState *state = State(pnode->GetId());
+ if (state == nullptr) return; // shouldn't be possible, but just in case
+ // Don't evict our protected peers
+ if (state->m_chain_sync.m_protect) return;
+ if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) {
+ worst_peer = pnode->GetId();
+ oldest_block_announcement = state->m_last_block_announcement;
+ }
+ });
+ if (worst_peer != -1) {
+ bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) {
+ // Only disconnect a peer that has been connected to us for
+ // some reasonable fraction of our check-frequency, to give
+ // it time for new information to have arrived.
+ // Also don't disconnect any peer we're trying to download a
+ // block from.
+ CNodeState &state = *State(pnode->GetId());
+ if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && state.nBlocksInFlight == 0) {
+ LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement);
+ pnode->fDisconnect = true;
+ return true;
+ } else {
+ LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), pnode->nTimeConnected, state.nBlocksInFlight);
+ return false;
+ }
+ });
+ if (disconnected) {
+ // If we disconnected an extra peer, that means we successfully
+ // connected to at least one peer after the last time we
+ // detected a stale tip. Don't try any more extra peers until
+ // we next detect a stale tip, to limit the load we put on the
+ // network from these extra connections.
+ connman->SetTryNewOutboundPeer(false);
+ }
+ }
+ }
+}
+
+void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams)
+{
+ if (connman == nullptr) return;
+
+ int64_t time_in_seconds = GetTime();
+
+ EvictExtraOutboundPeers(time_in_seconds);
+
+ if (time_in_seconds > m_stale_tip_check_time) {
+ LOCK(cs_main);
+ // Check whether our tip is stale, and if so, allow using an extra
+ // outbound peer
+ if (TipMayBeStale(consensusParams)) {
+ LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update);
+ connman->SetTryNewOutboundPeer(true);
+ } else if (connman->GetTryNewOutboundPeer()) {
+ connman->SetTryNewOutboundPeer(false);
+ }
+ m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL;
+ }
+}
+
class CompareInvMempoolOrder
{
CTxMemPool *mp;
public:
- CompareInvMempoolOrder(CTxMemPool *_mempool)
+ explicit CompareInvMempoolOrder(CTxMemPool *_mempool)
{
mp = _mempool;
}
@@ -2796,7 +3129,7 @@ public:
}
};
-bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptMsgProc)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@@ -2828,11 +3161,11 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING));
}
}
@@ -2867,14 +3200,14 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
@@ -2901,7 +3234,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
}
}
@@ -2910,7 +3243,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
// transactions become unconfirmed and spams other nodes.
if (!fReindex && !fImporting && !IsInitialBlockDownload())
{
- GetMainSignals().Broadcast(nTimeBestReceived, &connman);
+ GetMainSignals().Broadcast(nTimeBestReceived, connman);
}
//
@@ -2994,10 +3327,10 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
LOCK(cs_most_recent_block);
if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
else {
CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness);
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
fGotBlockFromCache = true;
}
@@ -3007,7 +3340,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
@@ -3020,7 +3353,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->GetId());
}
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
state.pindexBestHeaderSent = pBestIndex;
} else
fRevertToInv = true;
@@ -3066,7 +3399,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
for (const uint256& hash : pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -3112,7 +3445,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
pto->filterInventoryKnown.insert(hash);
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -3178,7 +3511,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
}
}
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
pto->filterInventoryKnown.insert(hash);
@@ -3186,7 +3519,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
}
}
if (!vInv.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
nNow = GetTimeMicros();
@@ -3245,6 +3578,9 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
}
}
+ // Check that outbound peers have reasonable chains
+ // GetTime() is used by this anti-DoS logic so we can test this using mocktime
+ ConsiderEviction(pto, GetTime());
//
// Message: getdata (blocks)
@@ -3281,7 +3617,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
}
} else {
@@ -3291,7 +3627,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
//
// Message: feefilter
@@ -3308,7 +3644,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
// We always have a fee filter of at least minRelayTxFee
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
if (filterToSend != pto->lastSentFeeFilter) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->lastSentFeeFilter = filterToSend;
}
pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
diff --git a/src/net_processing.h b/src/net_processing.h
index db6d81e6b6..3fc1e05835 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -6,8 +6,9 @@
#ifndef BITCOIN_NET_PROCESSING_H
#define BITCOIN_NET_PROCESSING_H
-#include "net.h"
-#include "validationinterface.h"
+#include <net.h>
+#include <validationinterface.h>
+#include <consensus/params.h>
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
@@ -21,23 +22,51 @@ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
* Timeout = base + per_header * (expected number of headers) */
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header
+/** Protect at least this many outbound peers from disconnection due to slow/
+ * behind headers chain.
+ */
+static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4;
+/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */
+static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes
+/** How frequently to check for stale tips, in seconds */
+static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes
+/** How frequently to check for extra outbound peers and disconnect, in seconds */
+static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45;
+/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */
+static constexpr int64_t MINIMUM_CONNECT_TIME = 30;
-/** Register with a network node to receive its signals */
-void RegisterNodeSignals(CNodeSignals& nodeSignals);
-/** Unregister a network node */
-void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-
-class PeerLogicValidation : public CValidationInterface {
+class PeerLogicValidation : public CValidationInterface, public NetEventsInterface {
private:
- CConnman* connman;
+ CConnman* const connman;
public:
- PeerLogicValidation(CConnman* connmanIn);
+ explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler);
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
void BlockChecked(const CBlock& block, const CValidationState& state) override;
void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;
+
+
+ void InitializeNode(CNode* pnode) override;
+ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override;
+ /** Process protocol messages received from a given node */
+ bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
+ /**
+ * Send queued protocol messages to be sent to a give node.
+ *
+ * @param[in] pto The node which we are sending messages to.
+ * @param[in] interrupt Interrupt condition for processing threads
+ * @return True if there is more work to be done
+ */
+ bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override;
+
+ void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
+ void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
+ void EvictExtraOutboundPeers(int64_t time_in_seconds);
+
+private:
+ int64_t m_stale_tip_check_time; //! Next time to check for stale tip
};
struct CNodeStateStats {
@@ -52,16 +81,4 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch);
-/** Process protocol messages received from a given node */
-bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interrupt);
-/**
- * Send queued protocol messages to be sent to a give node.
- *
- * @param[in] pto The node which we are sending messages to.
- * @param[in] connman The connection manager for that node.
- * @param[in] interrupt Interrupt condition for processing threads
- * @return True if there is more work to be done
- */
-bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interrupt);
-
#endif // BITCOIN_NET_PROCESSING_H
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index b8a261c921..fa1c191559 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -3,14 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifdef HAVE_CONFIG_H
-#include "config/bitcoin-config.h"
-#endif
-
-#include "netaddress.h"
-#include "hash.h"
-#include "utilstrencodings.h"
-#include "tinyformat.h"
+#include <netaddress.h>
+#include <hash.h>
+#include <utilstrencodings.h>
+#include <tinyformat.h>
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
diff --git a/src/netaddress.h b/src/netaddress.h
index 57ce897db5..3b542b4748 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -6,11 +6,11 @@
#define BITCOIN_NETADDRESS_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "serialize.h"
+#include <compat.h>
+#include <serialize.h>
#include <stdint.h>
#include <string>
@@ -36,7 +36,7 @@ class CNetAddr
public:
CNetAddr();
- CNetAddr(const struct in_addr& ipv4Addr);
+ explicit CNetAddr(const struct in_addr& ipv4Addr);
void Init();
void SetIP(const CNetAddr& ip);
@@ -82,7 +82,7 @@ class CNetAddr
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
- CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
+ explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
@@ -146,7 +146,7 @@ class CService : public CNetAddr
CService();
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
- CService(const struct sockaddr_in& addr);
+ explicit CService(const struct sockaddr_in& addr);
void Init();
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
@@ -160,7 +160,7 @@ class CService : public CNetAddr
std::string ToStringIPPort() const;
CService(const struct in6_addr& ipv6Addr, unsigned short port);
- CService(const struct sockaddr_in6& addr);
+ explicit CService(const struct sockaddr_in6& addr);
ADD_SERIALIZE_METHODS;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 05f9f6961c..f4232fc42a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -3,18 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifdef HAVE_CONFIG_H
-#include "config/bitcoin-config.h"
-#endif
-
-#include "netbase.h"
+#include <netbase.h>
-#include "hash.h"
-#include "sync.h"
-#include "uint256.h"
-#include "random.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <sync.h>
+#include <uint256.h>
+#include <random.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <atomic>
@@ -184,6 +180,48 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout;
}
+/** SOCKS version */
+enum SOCKSVersion: uint8_t {
+ SOCKS4 = 0x04,
+ SOCKS5 = 0x05
+};
+
+/** Values defined for METHOD in RFC1928 */
+enum SOCKS5Method: uint8_t {
+ NOAUTH = 0x00, //! No authentication required
+ GSSAPI = 0x01, //! GSSAPI
+ USER_PASS = 0x02, //! Username/password
+ NO_ACCEPTABLE = 0xff, //! No acceptable methods
+};
+
+/** Values defined for CMD in RFC1928 */
+enum SOCKS5Command: uint8_t {
+ CONNECT = 0x01,
+ BIND = 0x02,
+ UDP_ASSOCIATE = 0x03
+};
+
+/** Values defined for REP in RFC1928 */
+enum SOCKS5Reply: uint8_t {
+ SUCCEEDED = 0x00, //! Succeeded
+ GENFAILURE = 0x01, //! General failure
+ NOTALLOWED = 0x02, //! Connection not allowed by ruleset
+ NETUNREACHABLE = 0x03, //! Network unreachable
+ HOSTUNREACHABLE = 0x04, //! Network unreachable
+ CONNREFUSED = 0x05, //! Connection refused
+ TTLEXPIRED = 0x06, //! TTL expired
+ CMDUNSUPPORTED = 0x07, //! Command not supported
+ ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+};
+
+/** Values defined for ATYPE in RFC1928 */
+enum SOCKS5Atyp: uint8_t {
+ IPV4 = 0x01,
+ DOMAINNAME = 0x03,
+ IPV6 = 0x04,
+};
+
+/** Status codes that can be returned by InterruptibleRecv */
enum class IntrRecvError {
OK,
Timeout,
@@ -203,7 +241,7 @@ enum class IntrRecvError {
*
* @note This function requires that hSocket is in non-blocking mode.
*/
-static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, const SOCKET& hSocket)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
@@ -211,7 +249,7 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
// to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
- ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
+ ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
if (ret > 0) {
len -= ret;
data += ret;
@@ -242,66 +280,73 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
+/** Credentials for proxy authentication */
struct ProxyCredentials
{
std::string username;
std::string password;
};
-std::string Socks5ErrorString(int err)
+/** Convert SOCKS5 reply to an error message */
+std::string Socks5ErrorString(uint8_t err)
{
switch(err) {
- case 0x01: return "general failure";
- case 0x02: return "connection not allowed";
- case 0x03: return "network unreachable";
- case 0x04: return "host unreachable";
- case 0x05: return "connection refused";
- case 0x06: return "TTL expired";
- case 0x07: return "protocol error";
- case 0x08: return "address type not supported";
- default: return "unknown";
+ case SOCKS5Reply::GENFAILURE:
+ return "general failure";
+ case SOCKS5Reply::NOTALLOWED:
+ return "connection not allowed";
+ case SOCKS5Reply::NETUNREACHABLE:
+ return "network unreachable";
+ case SOCKS5Reply::HOSTUNREACHABLE:
+ return "host unreachable";
+ case SOCKS5Reply::CONNREFUSED:
+ return "connection refused";
+ case SOCKS5Reply::TTLEXPIRED:
+ return "TTL expired";
+ case SOCKS5Reply::CMDUNSUPPORTED:
+ return "protocol error";
+ case SOCKS5Reply::ATYPEUNSUPPORTED:
+ return "address type not supported";
+ default:
+ return "unknown";
}
}
/** Connect using SOCKS5 (as described in RFC1928) */
-static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
+static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
{
IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
- CloseSocket(hSocket);
return error("Hostname too long");
}
// Accepted authentication methods
std::vector<uint8_t> vSocks5Init;
- vSocks5Init.push_back(0x05);
+ vSocks5Init.push_back(SOCKSVersion::SOCKS5);
if (auth) {
- vSocks5Init.push_back(0x02); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
- vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
+ vSocks5Init.push_back(0x02); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
+ vSocks5Init.push_back(SOCKS5Method::USER_PASS);
} else {
- vSocks5Init.push_back(0x01); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+ vSocks5Init.push_back(0x01); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
- CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet1[2];
+ uint8_t pchRet1[2];
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false;
}
- if (pchRet1[0] != 0x05) {
- CloseSocket(hSocket);
+ if (pchRet1[0] != SOCKSVersion::SOCKS5) {
return error("Proxy failed to initialize");
}
- if (pchRet1[1] == 0x02 && auth) {
+ if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
// Perform username/password authentication (as described in RFC1929)
std::vector<uint8_t> vAuth;
- vAuth.push_back(0x01);
+ vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
if (auth->username.size() > 255 || auth->password.size() > 255)
return error("Proxy username or password too long");
vAuth.push_back(auth->username.size());
@@ -310,42 +355,36 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) {
- CloseSocket(hSocket);
return error("Error sending authentication to proxy");
}
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
- char pchRetA[2];
+ uint8_t pchRetA[2];
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading proxy authentication response");
}
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
- CloseSocket(hSocket);
return error("Proxy authentication unsuccessful");
}
- } else if (pchRet1[1] == 0x00) {
+ } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
// Perform no authentication
} else {
- CloseSocket(hSocket);
return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
}
std::vector<uint8_t> vSocks5;
- vSocks5.push_back(0x05); // VER protocol version
- vSocks5.push_back(0x01); // CMD CONNECT
- vSocks5.push_back(0x00); // RSV Reserved
- vSocks5.push_back(0x03); // ATYP DOMAINNAME
+ vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
+ vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
+ vSocks5.push_back(0x00); // RSV Reserved must be 0
+ vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
vSocks5.push_back((port >> 0) & 0xFF);
ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) {
- CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet2[4];
+ uint8_t pchRet2[4];
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
if (recvr == IntrRecvError::Timeout) {
/* If a timeout happens here, this effectively means we timed out while connecting
* to the remote node. This is very common for Tor, so do not print an
@@ -355,64 +394,62 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error while reading proxy response");
}
}
- if (pchRet2[0] != 0x05) {
- CloseSocket(hSocket);
+ if (pchRet2[0] != SOCKSVersion::SOCKS5) {
return error("Proxy failed to accept request");
}
- if (pchRet2[1] != 0x00) {
+ if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
// Failures to connect to a peer that are not proxy errors
- CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
return false;
}
- if (pchRet2[2] != 0x00) {
- CloseSocket(hSocket);
+ if (pchRet2[2] != 0x00) { // Reserved field must be 0
return error("Error: malformed proxy response");
}
- char pchRet3[256];
+ uint8_t pchRet3[256];
switch (pchRet2[3])
{
- case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x03:
+ case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::DOMAINNAME:
{
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (recvr != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break;
}
- default: CloseSocket(hSocket); return error("Error: malformed proxy response");
+ default: return error("Error: malformed proxy response");
}
if (recvr != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
- CloseSocket(hSocket);
return error("Error reading from proxy");
}
LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
return true;
}
-bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
+SOCKET CreateSocket(const CService &addrConnect)
{
- hSocketRet = INVALID_SOCKET;
-
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
- LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
- return false;
+ LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
+ return INVALID_SOCKET;
}
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
- return false;
+ return INVALID_SOCKET;
+
+ if (!IsSelectableSocket(hSocket)) {
+ CloseSocket(hSocket);
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ return INVALID_SOCKET;
+ }
#ifdef SO_NOSIGPIPE
int set = 1;
@@ -426,9 +463,23 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
// Set to non-blocking
if (!SetSocketNonBlocking(hSocket, true)) {
CloseSocket(hSocket);
- return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
+ LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
}
+ return hSocket;
+}
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout)
+{
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ if (hSocket == INVALID_SOCKET) {
+ LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
+ return false;
+ }
+ if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
+ LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
+ return false;
+ }
if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
@@ -443,13 +494,11 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (nRet == 0)
{
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
- CloseSocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
socklen_t nRetSize = sizeof(nRet);
@@ -460,13 +509,11 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
if (nRet != 0)
{
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
- CloseSocket(hSocket);
return false;
}
}
@@ -477,12 +524,9 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- CloseSocket(hSocket);
return false;
}
}
-
- hSocketRet = hSocket;
return true;
}
@@ -534,9 +578,8 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
{
- SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) {
if (outProxyConnectionFailed)
@@ -548,57 +591,16 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
- if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) {
return false;
+ }
} else {
- if (!Socks5(strDest, (unsigned short)port, 0, hSocket))
+ if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) {
return false;
- }
-
- hSocketRet = hSocket;
- return true;
-}
-
-bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
-{
- proxyType proxy;
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- if (GetProxy(addrDest.GetNetwork(), proxy))
- return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed);
- else // no proxy needed (none set for target network)
- return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
-}
-
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
-{
- std::string strDest;
- int port = portDefault;
-
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- SplitHostPort(std::string(pszDest), port, strDest);
-
- proxyType proxy;
- GetNameProxy(proxy);
-
- std::vector<CService> addrResolved;
- if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
- if (addrResolved.size() > 0) {
- addr = addrResolved[GetRand(addrResolved.size())];
- return ConnectSocket(addr, hSocketRet, nTimeout);
}
}
-
- addr = CService();
-
- if (!HaveNameProxy())
- return false;
- return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
+ return true;
}
-
bool LookupSubNet(const char* pszName, CSubNet& ret)
{
std::string strSubnet(pszName);
diff --git a/src/netbase.h b/src/netbase.h
index 941da31f9c..c89bd5b88f 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -6,12 +6,12 @@
#define BITCOIN_NETBASE_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "netaddress.h"
-#include "serialize.h"
+#include <compat.h>
+#include <netaddress.h>
+#include <serialize.h>
#include <stdint.h>
#include <string>
@@ -29,7 +29,7 @@ class proxyType
{
public:
proxyType(): randomize_credentials(false) {}
- proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
+ explicit proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
bool IsValid() const { return proxy.IsValid(); }
@@ -44,14 +44,16 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
+bool GetNameProxy(proxyType &nameProxyOut);
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup);
bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup);
bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
CService LookupNumeric(const char *pszName, int portDefault = 0);
bool LookupSubNet(const char *pszName, CSubNet& subnet);
-bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed = 0);
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = 0);
+SOCKET CreateSocket(const CService &addrConnect);
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout);
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index 8e8a6e4a02..ea7fccacb2 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -6,13 +6,13 @@
#ifndef BITCOIN_NETMESSAGEMAKER_H
#define BITCOIN_NETMESSAGEMAKER_H
-#include "net.h"
-#include "serialize.h"
+#include <net.h>
+#include <serialize.h>
class CNetMsgMaker
{
public:
- CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
+ explicit CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
template <typename... Args>
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const
diff --git a/src/noui.cpp b/src/noui.cpp
index 4bfb75fa29..feb3464a56 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "noui.h"
+#include <noui.h>
-#include "ui_interface.h"
-#include "util.h"
+#include <ui_interface.h>
+#include <util.h>
#include <cstdio>
#include <stdint.h>
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index a089c02284..26c44ee0cf 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "feerate.h"
+#include <policy/feerate.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
const std::string CURRENCY_UNIT = "BTC";
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 565da6c154..35b1b23786 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_POLICY_FEERATE_H
#define BITCOIN_POLICY_FEERATE_H
-#include "amount.h"
-#include "serialize.h"
+#include <amount.h>
+#include <serialize.h>
#include <string>
@@ -20,13 +20,17 @@ class CFeeRate
{
private:
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
+
public:
/** Fee rate of 0 satoshis per kB */
CFeeRate() : nSatoshisPerK(0) { }
- explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
+ template<typename I>
+ CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
+ // We've previously had bugs creep in from silent double->int conversion...
+ static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
+ }
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
- CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/**
* Return the fee in satoshis for the given size in bytes.
*/
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index b9476407cf..dc88c4f91a 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -3,16 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/fees.h"
-#include "policy/policy.h"
+#include <policy/fees.h>
+#include <policy/policy.h>
-#include "amount.h"
-#include "clientversion.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "streams.h"
-#include "txmempool.h"
-#include "util.h"
+#include <clientversion.h>
+#include <primitives/transaction.h>
+#include <streams.h>
+#include <txmempool.h>
+#include <util.h>
static constexpr double INF_FEERATE = 1e99;
@@ -180,6 +178,7 @@ TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
: buckets(defaultBuckets), bucketMap(defaultBucketMap)
{
decay = _decay;
+ assert(_scale != 0 && "_scale must be non-zero");
scale = _scale;
confAvg.resize(maxPeriods);
for (unsigned int i = 0; i < maxPeriods; i++) {
@@ -418,6 +417,9 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
}
filein >> scale;
+ if (scale == 0) {
+ throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
+ }
}
filein >> avg;
@@ -503,6 +505,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
}
}
if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
+ assert(scale != 0);
unsigned int periodsAgo = blocksAgo / scale;
for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
failAvg[i][bucketindex]++;
@@ -543,16 +546,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
bucketMap[INF_FEERATE] = bucketIndex;
assert(bucketMap.size() == buckets.size());
- feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);
- shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);
- longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);
+ feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
+ shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
+ longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
}
CBlockPolicyEstimator::~CBlockPolicyEstimator()
{
- delete feeStats;
- delete shortStats;
- delete longStats;
}
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
@@ -685,16 +685,16 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
double sufficientTxs = SUFFICIENT_FEETXS;
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
- stats = shortStats;
+ stats = shortStats.get();
sufficientTxs = SUFFICIENT_TXS_SHORT;
break;
}
case FeeEstimateHorizon::MED_HALFLIFE: {
- stats = feeStats;
+ stats = feeStats.get();
break;
}
case FeeEstimateHorizon::LONG_HALFLIFE: {
- stats = longStats;
+ stats = longStats.get();
break;
}
default: {
@@ -714,7 +714,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
if (median < 0)
return CFeeRate(0);
- return CFeeRate(median);
+ return CFeeRate(llround(median));
}
unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
@@ -901,7 +901,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
if (median < 0) return CFeeRate(0); // error condition
- return CFeeRate(median);
+ return CFeeRate(llround(median));
}
@@ -997,12 +997,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
}
// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
- delete feeStats;
- delete shortStats;
- delete longStats;
- feeStats = fileFeeStats.release();
- shortStats = fileShortStats.release();
- longStats = fileLongStats.release();
+ feeStats = std::move(fileFeeStats);
+ shortStats = std::move(fileShortStats);
+ longStats = std::move(fileLongStats);
nBestSeenHeight = nFileBestSeenHeight;
historicalFirst = nFileHistoricalFirst;
@@ -1043,5 +1040,5 @@ CAmount FeeFilterRounder::round(CAmount currentMinFee)
if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
it--;
}
- return *it;
+ return static_cast<CAmount>(*it);
}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index f4ef793643..6528560f52 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -5,11 +5,11 @@
#ifndef BITCOIN_POLICYESTIMATOR_H
#define BITCOIN_POLICYESTIMATOR_H
-#include "amount.h"
-#include "feerate.h"
-#include "uint256.h"
-#include "random.h"
-#include "sync.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <uint256.h>
+#include <random.h>
+#include <sync.h>
#include <map>
#include <string>
@@ -245,9 +245,9 @@ private:
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats* feeStats;
- TxConfirmStats* shortStats;
- TxConfirmStats* longStats;
+ std::unique_ptr<TxConfirmStats> feeStats;
+ std::unique_ptr<TxConfirmStats> shortStats;
+ std::unique_ptr<TxConfirmStats> longStats;
unsigned int trackedTxs;
unsigned int untrackedTxs;
@@ -284,7 +284,7 @@ private:
public:
/** Create new FeeFilterRounder */
- FeeFilterRounder(const CFeeRate& minIncrementalFee);
+ explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
/** Quantize a minimum fee for privacy purpose before broadcast **/
CAmount round(CAmount currentMinFee);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 605e3e0696..b69bed5d6f 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -5,14 +5,14 @@
// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
-#include "policy/policy.h"
+#include <policy/policy.h>
-#include "consensus/validation.h"
-#include "validation.h"
-#include "coins.h"
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <consensus/validation.h>
+#include <validation.h>
+#include <coins.h>
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
@@ -54,23 +54,6 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
- /**
- * Check transaction inputs to mitigate two
- * potential denial-of-service attacks:
- *
- * 1. scriptSigs with extra data stuffed into them,
- * not consumed by scriptPubKey (or P2SH script)
- * 2. P2SH scripts with a crazy number of expensive
- * CHECKSIG/CHECKMULTISIG operations
- *
- * Why bother? To avoid denial-of-service attacks; an attacker
- * can submit a standard HASH... OP_EQUAL transaction,
- * which will get accepted into blocks. The redemption
- * script can be anything; an attacker could use a very
- * expensive-to-check-upon-redemption script like:
- * DUP CHECKSIG DROP ... repeated 100 times... OP_1
- */
-
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
std::vector<std::vector<unsigned char> > vSolutions;
@@ -93,7 +76,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool w
else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
return false;
- return whichType != TX_NONSTANDARD;
+ return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
}
bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
@@ -160,6 +143,22 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
return true;
}
+/**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 2. P2SH scripts with a crazy number of expensive
+ * CHECKSIG/CHECKMULTISIG operations
+ *
+ * Why bother? To avoid denial-of-service attacks; an attacker
+ * can submit a standard HASH... OP_EQUAL transaction,
+ * which will get accepted into blocks. The redemption
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
diff --git a/src/policy/policy.h b/src/policy/policy.h
index c06820f84e..f3f8ebbbb4 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -6,20 +6,18 @@
#ifndef BITCOIN_POLICY_POLICY_H
#define BITCOIN_POLICY_POLICY_H
-#include "consensus/consensus.h"
-#include "feerate.h"
-#include "script/interpreter.h"
-#include "script/standard.h"
+#include <consensus/consensus.h>
+#include <policy/feerate.h>
+#include <script/interpreter.h>
+#include <script/standard.h>
#include <string>
class CCoinsViewCache;
class CTxOut;
-/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
+static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000;
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
/** The maximum weight for transactions we're willing to relay/mine */
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 755ef83c9a..e9692d4b48 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/rbf.h"
+#include <policy/rbf.h>
bool SignalsOptInRBF(const CTransaction &tx)
{
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 22c73f3319..1a5218e120 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_POLICY_RBF_H
#define BITCOIN_POLICY_RBF_H
-#include "txmempool.h"
+#include <txmempool.h>
static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;
diff --git a/src/pow.cpp b/src/pow.cpp
index 7d87c6bbb7..cecb54ca7b 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "pow.h"
+#include <pow.h>
-#include "arith_uint256.h"
-#include "chain.h"
-#include "primitives/block.h"
-#include "uint256.h"
+#include <arith_uint256.h>
+#include <chain.h>
+#include <primitives/block.h>
+#include <uint256.h>
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
diff --git a/src/pow.h b/src/pow.h
index e203f492a1..db2f5343b5 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_POW_H
#define BITCOIN_POW_H
-#include "consensus/params.h"
+#include <consensus/params.h>
#include <stdint.h>
diff --git a/src/prevector.h b/src/prevector.h
index f7bde8911a..eb29b3ae7e 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_PREVECTOR_H_
-#define _BITCOIN_PREVECTOR_H_
+#ifndef BITCOIN_PREVECTOR_H
+#define BITCOIN_PREVECTOR_H
#include <assert.h>
#include <stdlib.h>
@@ -514,4 +514,4 @@ public:
};
#pragma pack(pop)
-#endif
+#endif // BITCOIN_PREVECTOR_H
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 3774ac3e4b..9e20565511 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/block.h"
+#include <primitives/block.h>
-#include "hash.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
-#include "crypto/common.h"
+#include <hash.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
+#include <crypto/common.h>
uint256 CBlockHeader::GetHash() const
{
diff --git a/src/primitives/block.h b/src/primitives/block.h
index c90a1dfa64..4957958c6a 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_PRIMITIVES_BLOCK_H
#define BITCOIN_PRIMITIVES_BLOCK_H
-#include "primitives/transaction.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <serialize.h>
+#include <uint256.h>
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
@@ -129,7 +129,7 @@ struct CBlockLocator
CBlockLocator() {}
- CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
+ explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
ADD_SERIALIZE_METHODS;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 9b6a814e1f..d8230d1423 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/transaction.h"
+#include <primitives/transaction.h>
-#include "hash.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
std::string COutPoint::ToString() const
{
@@ -55,7 +55,7 @@ std::string CTxOut::ToString() const
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
-CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
uint256 CMutableTransaction::GetHash() const
{
@@ -76,9 +76,9 @@ uint256 CTransaction::GetWitnessHash() const
}
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
-CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {}
-CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
-CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash() {}
+CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CAmount CTransaction::GetValueOut() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 041034bb8b..32f45e5748 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -7,10 +7,10 @@
#define BITCOIN_PRIMITIVES_TRANSACTION_H
#include <stdint.h>
-#include "amount.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <amount.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <uint256.h>
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
@@ -278,9 +278,9 @@ public:
// actually immutable; deserialization and assignment are implemented,
// and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
- const int32_t nVersion;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
+ const int32_t nVersion;
const uint32_t nLockTime;
private:
@@ -361,9 +361,9 @@ public:
/** A mutable version of CTransaction. */
struct CMutableTransaction
{
- int32_t nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
+ int32_t nVersion;
uint32_t nLockTime;
CMutableTransaction();
diff --git a/src/protocol.cpp b/src/protocol.cpp
index da87e40091..8c34c4196e 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "protocol.h"
+#include <protocol.h>
-#include "util.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilstrencodings.h>
#ifndef WIN32
# include <arpa/inet.h>
diff --git a/src/protocol.h b/src/protocol.h
index 7890bb627d..cf1d40db77 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -10,10 +10,10 @@
#ifndef BITCOIN_PROTOCOL_H
#define BITCOIN_PROTOCOL_H
-#include "netaddress.h"
-#include "serialize.h"
-#include "uint256.h"
-#include "version.h"
+#include <netaddress.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <version.h>
#include <stdint.h>
#include <string>
@@ -27,19 +27,16 @@
class CMessageHeader
{
public:
- enum {
- MESSAGE_START_SIZE = 4,
- COMMAND_SIZE = 12,
- MESSAGE_SIZE_SIZE = 4,
- CHECKSUM_SIZE = 4,
-
- MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,
- CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,
- HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE
- };
+ static constexpr size_t MESSAGE_START_SIZE = 4;
+ static constexpr size_t COMMAND_SIZE = 12;
+ static constexpr size_t MESSAGE_SIZE_SIZE = 4;
+ static constexpr size_t CHECKSUM_SIZE = 4;
+ static constexpr size_t MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE;
+ static constexpr size_t CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE;
+ static constexpr size_t HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE;
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
- CMessageHeader(const MessageStartChars& pchMessageStartIn);
+ explicit CMessageHeader(const MessageStartChars& pchMessageStartIn);
CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
@@ -249,9 +246,8 @@ const std::vector<std::string> &getAllNetMessageTypes();
enum ServiceFlags : uint64_t {
// Nothing
NODE_NONE = 0,
- // NODE_NETWORK means that the node is capable of serving the block chain. It is currently
- // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
- // network services but don't provide them.
+ // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
+ // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
NODE_NETWORK = (1 << 0),
// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
@@ -267,6 +263,10 @@ enum ServiceFlags : uint64_t {
// NODE_XTHIN means the node supports Xtreme Thinblocks
// If this is turned off then the node will not service nor make xthin requests
NODE_XTHIN = (1 << 4),
+ // NODE_NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only
+ // serving the last 288 (2 day) blocks
+ // See BIP159 for details on how this is implemented.
+ NODE_NETWORK_LIMITED = (1 << 10),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
@@ -277,6 +277,43 @@ enum ServiceFlags : uint64_t {
// BIP process.
};
+/**
+ * Gets the set of service flags which are "desirable" for a given peer.
+ *
+ * These are the flags which are required for a peer to support for them
+ * to be "interesting" to us, ie for us to wish to use one of our few
+ * outbound connection slots for or for us to wish to prioritize keeping
+ * their connection around.
+ *
+ * Relevant service flags may be peer- and state-specific in that the
+ * version of the peer may determine which flags are required (eg in the
+ * case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
+ * unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
+ * case NODE_NETWORK_LIMITED suffices).
+ *
+ * Thus, generally, avoid calling with peerServices == NODE_NONE.
+ */
+static ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
+ return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
+}
+
+/**
+ * A shortcut for (services & GetDesirableServiceFlags(services))
+ * == GetDesirableServiceFlags(services), ie determines whether the given
+ * set of service flags are sufficient for a peer to be "relevant".
+ */
+static inline bool HasAllDesirableServiceFlags(ServiceFlags services) {
+ return !(GetDesirableServiceFlags(services) & (~services));
+}
+
+/**
+ * Checks if a peer with the given service flags may be capable of having a
+ * robust address-storage DB. Currently an alias for checking NODE_NETWORK.
+ */
+static inline bool MayHaveUsefulAddressDB(ServiceFlags services) {
+ return services & NODE_NETWORK;
+}
+
/** A CService with information about it as peer */
class CAddress : public CService
{
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 2da7be783f..7f5ec1e8de 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "pubkey.h"
+#include <pubkey.h>
#include <secp256k1.h>
#include <secp256k1_recovery.h>
@@ -126,7 +126,6 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
return 0;
}
spos = pos;
- pos += slen;
/* Ignore leading zeroes in R */
while (rlen > 0 && input[rpos] == 0) {
diff --git a/src/pubkey.h b/src/pubkey.h
index dbf0e23f20..c9f3c18eb3 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_PUBKEY_H
#define BITCOIN_PUBKEY_H
-#include "hash.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <hash.h>
+#include <serialize.h>
+#include <uint256.h>
#include <stdexcept>
#include <vector>
@@ -30,7 +30,7 @@ class CKeyID : public uint160
{
public:
CKeyID() : uint160() {}
- CKeyID(const uint160& in) : uint160(in) {}
+ explicit CKeyID(const uint160& in) : uint160(in) {}
};
typedef uint256 ChainCode;
@@ -88,7 +88,7 @@ public:
}
//! Construct a public key from a byte vector.
- CPubKey(const std::vector<unsigned char>& _vch)
+ explicit CPubKey(const std::vector<unsigned char>& _vch)
{
Set(_vch.begin(), _vch.end());
}
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index f295bd4689..dda8dce391 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -3,18 +3,18 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "addressbookpage.h"
-#include "ui_addressbookpage.h"
+#include <qt/addressbookpage.h>
+#include <qt/forms/ui_addressbookpage.h>
-#include "addresstablemodel.h"
-#include "bitcoingui.h"
-#include "csvmodelwriter.h"
-#include "editaddressdialog.h"
-#include "guiutil.h"
-#include "platformstyle.h"
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoingui.h>
+#include <qt/csvmodelwriter.h>
+#include <qt/editaddressdialog.h>
+#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
#include <QIcon>
#include <QMenu>
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 2fa032abdc..1d16940acb 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addresstablemodel.h"
+#include <qt/addresstablemodel.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
-#include "base58.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <wallet/wallet.h>
#include <QFont>
@@ -82,14 +82,14 @@ public:
LOCK(wallet->cs_wallet);
for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook)
{
- const CBitcoinAddress& address = item.first;
- bool fMine = IsMine(*wallet, address.Get());
+ const CTxDestination& address = item.first;
+ bool fMine = IsMine(*wallet, address);
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(item.second.purpose), fMine);
const std::string& strName = item.second.name;
cachedAddressTable.append(AddressTableEntry(addressType,
QString::fromStdString(strName),
- QString::fromStdString(address.ToString())));
+ QString::fromStdString(EncodeDestination(address))));
}
}
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
@@ -246,7 +246,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
if(role == Qt::EditRole)
{
LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
- CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get();
+ CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
if(index.column() == Label)
{
// Do nothing, if old label == new label
@@ -257,7 +257,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
}
wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
} else if(index.column() == Address) {
- CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get();
+ CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
if(boost::get<CNoDestination>(&newAddress))
{
@@ -358,7 +358,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Check for duplicate addresses
{
LOCK(wallet->cs_wallet);
- if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
+ if(wallet->mapAddressBook.count(DecodeDestination(strAddress)))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
@@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
- strAddress = CBitcoinAddress(newKey.GetID()).ToString();
+ strAddress = EncodeDestination(newKey.GetID());
}
else
{
@@ -394,7 +394,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Add entry
{
LOCK(wallet->cs_wallet);
- wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel,
+ wallet->SetAddressBook(DecodeDestination(strAddress), strLabel,
(type == Send ? "send" : "receive"));
}
return QString::fromStdString(strAddress);
@@ -412,7 +412,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
}
{
LOCK(wallet->cs_wallet);
- wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get());
+ wallet->DelAddressBook(DecodeDestination(rec->address.toStdString()));
}
return true;
}
@@ -423,8 +423,8 @@ QString AddressTableModel::labelForAddress(const QString &address) const
{
{
LOCK(wallet->cs_wallet);
- CBitcoinAddress address_parsed(address.toStdString());
- std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
+ CTxDestination destination = DecodeDestination(address.toStdString());
+ std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination);
if (mi != wallet->mapAddressBook.end())
{
return QString::fromStdString(mi->second.name);
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index e9f5c77a5b..a720ac956b 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -3,16 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "askpassphrasedialog.h"
-#include "ui_askpassphrasedialog.h"
+#include <qt/askpassphrasedialog.h>
+#include <qt/forms/ui_askpassphrasedialog.h>
-#include "guiconstants.h"
-#include "walletmodel.h"
+#include <qt/guiconstants.h>
+#include <qt/walletmodel.h>
-#include "support/allocators/secure.h"
+#include <support/allocators/secure.h>
#include <QKeyEvent>
#include <QMessageBox>
@@ -70,6 +70,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) :
break;
}
textChanged();
+ connect(ui->toggleShowPasswordButton, SIGNAL(toggled(bool)), this, SLOT(toggleShowPassword(bool)));
connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
@@ -234,6 +235,15 @@ bool AskPassphraseDialog::event(QEvent *event)
return QWidget::event(event);
}
+void AskPassphraseDialog::toggleShowPassword(bool show)
+{
+ ui->toggleShowPasswordButton->setDown(show);
+ const auto mode = show ? QLineEdit::Normal : QLineEdit::Password;
+ ui->passEdit1->setEchoMode(mode);
+ ui->passEdit2->setEchoMode(mode);
+ ui->passEdit3->setEchoMode(mode);
+}
+
bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
/* Detect Caps Lock.
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 34bf7ccb31..7c6acc4650 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -43,6 +43,7 @@ private:
private Q_SLOTS:
void textChanged();
void secureClearPassFields();
+ void toggleShowPassword(bool);
protected:
bool event(QEvent *event);
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index f8a99506c1..c96bdfd5d7 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bantablemodel.h"
+#include <qt/bantablemodel.h>
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
-#include "sync.h"
-#include "utiltime.h"
+#include <sync.h>
+#include <utiltime.h>
#include <QDebug>
#include <QList>
@@ -55,11 +55,11 @@ public:
#if QT_VERSION >= 0x040700
cachedBanlist.reserve(banMap.size());
#endif
- for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ for (const auto& entry : banMap)
{
CCombinedBan banEntry;
- banEntry.subnet = (*it).first;
- banEntry.banEntry = (*it).second;
+ banEntry.subnet = entry.first;
+ banEntry.banEntry = entry.second;
cachedBanlist.append(banEntry);
}
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
index 062cfdc931..dc69dee20a 100644
--- a/src/qt/bantablemodel.h
+++ b/src/qt/bantablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BANTABLEMODEL_H
#define BITCOIN_QT_BANTABLEMODEL_H
-#include "net.h"
+#include <net.h>
#include <QAbstractTableModel>
#include <QStringList>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 2b6bd354a0..557d7efcec 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -3,38 +3,38 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "bitcoingui.h"
-
-#include "chainparams.h"
-#include "clientmodel.h"
-#include "fs.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "intro.h"
-#include "networkstyle.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "splashscreen.h"
-#include "utilitydialog.h"
-#include "winshutdownmonitor.h"
+#include <qt/bitcoingui.h>
+
+#include <chainparams.h>
+#include <qt/clientmodel.h>
+#include <fs.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/intro.h>
+#include <qt/networkstyle.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/splashscreen.h>
+#include <qt/utilitydialog.h>
+#include <qt/winshutdownmonitor.h>
#ifdef ENABLE_WALLET
-#include "paymentserver.h"
-#include "walletmodel.h"
+#include <qt/paymentserver.h>
+#include <qt/walletmodel.h>
#endif
-#include "init.h"
-#include "rpc/server.h"
-#include "scheduler.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "warnings.h"
+#include <init.h>
+#include <rpc/server.h>
+#include <scheduler.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <warnings.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#endif
#include <stdint.h>
@@ -227,7 +227,7 @@ public:
void requestShutdown();
/// Get process return value
- int getReturnValue() { return returnValue; }
+ int getReturnValue() const { return returnValue; }
/// Get window identifier of QMainWindow (BitcoinGUI)
WId getMainWinId() const;
@@ -261,7 +261,7 @@ private:
void startThread();
};
-#include "bitcoin.moc"
+#include <qt/bitcoin.moc>
BitcoinCore::BitcoinCore():
QObject()
diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp
index d712705c43..e8d174bf29 100644
--- a/src/qt/bitcoinaddressvalidator.cpp
+++ b/src/qt/bitcoinaddressvalidator.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinaddressvalidator.h"
+#include <qt/bitcoinaddressvalidator.h>
-#include "base58.h"
+#include <base58.h>
/* Base58 characters are:
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
@@ -67,7 +67,7 @@ QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &po
if (((ch >= '0' && ch<='9') ||
(ch >= 'a' && ch<='z') ||
(ch >= 'A' && ch<='Z')) &&
- ch != 'l' && ch != 'I' && ch != '0' && ch != 'O')
+ ch != 'I' && ch != 'O') // Characters invalid in both Base58 and Bech32
{
// Alphanumeric and not a 'forbidden' character
}
@@ -89,9 +89,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po
{
Q_UNUSED(pos);
// Validate the passed Bitcoin address
- CBitcoinAddress addr(input.toStdString());
- if (addr.IsValid())
+ if (IsValidDestinationString(input.toStdString())) {
return QValidator::Acceptable;
+ }
return QValidator::Invalid;
}
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 73eb35a54e..0b21349c54 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinamountfield.h"
+#include <qt/bitcoinamountfield.h>
-#include "bitcoinunits.h"
-#include "guiconstants.h"
-#include "qvaluecombobox.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
+#include <qt/qvaluecombobox.h>
#include <QApplication>
#include <QAbstractSpinBox>
@@ -188,7 +188,7 @@ Q_SIGNALS:
void valueChanged();
};
-#include "bitcoinamountfield.moc"
+#include <qt/bitcoinamountfield.moc>
BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
QWidget(parent),
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index 2f03a3d171..659ecb416b 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BITCOINAMOUNTFIELD_H
#define BITCOIN_QT_BITCOINAMOUNTFIELD_H
-#include "amount.h"
+#include <amount.h>
#include <QWidget>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index e3970298e6..f925ec5359 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -2,39 +2,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
-#endif
-
-#include "bitcoingui.h"
-
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "modaloverlay.h"
-#include "networkstyle.h"
-#include "notificator.h"
-#include "openuridialog.h"
-#include "optionsdialog.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "rpcconsole.h"
-#include "utilitydialog.h"
+#include <qt/bitcoingui.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/modaloverlay.h>
+#include <qt/networkstyle.h>
+#include <qt/notificator.h>
+#include <qt/openuridialog.h>
+#include <qt/optionsdialog.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/rpcconsole.h>
+#include <qt/utilitydialog.h>
#ifdef ENABLE_WALLET
-#include "walletframe.h"
-#include "walletmodel.h"
+#include <qt/walletframe.h>
+#include <qt/walletmodel.h>
#endif // ENABLE_WALLET
#ifdef Q_OS_MAC
-#include "macdockiconhandler.h"
+#include <qt/macdockiconhandler.h>
#endif
-#include "chainparams.h"
-#include "init.h"
-#include "ui_interface.h"
-#include "util.h"
+#include <chainparams.h>
+#include <init.h>
+#include <ui_interface.h>
+#include <util.h>
#include <iostream>
@@ -123,7 +119,11 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *
spinnerFrame(0),
platformStyle(_platformStyle)
{
- GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
QString windowTitle = tr(PACKAGE_NAME) + " - ";
#ifdef ENABLE_WALLET
@@ -261,7 +261,8 @@ BitcoinGUI::~BitcoinGUI()
// Unsubscribe from notifications from core
unsubscribeFromCoreSignals();
- GUIUtil::saveWindowGeometry("nWindow", this);
+ QSettings settings;
+ settings.setValue("MainWindowGeometry", saveGeometry());
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide();
#ifdef Q_OS_MAC
@@ -454,6 +455,7 @@ void BitcoinGUI::createToolBars()
if(walletFrame)
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
+ toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
toolbar->setMovable(false);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index aa45ea1f0a..1647975fec 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -6,10 +6,10 @@
#define BITCOIN_QT_BITCOINGUI_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "amount.h"
+#include <amount.h>
#include <QLabel>
#include <QMainWindow>
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 4da414a4e3..c8614fdfe0 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinunits.h"
+#include <qt/bitcoinunits.h>
-#include "primitives/transaction.h"
+#include <primitives/transaction.h>
#include <QStringList>
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 6ef37de380..3f5a7fd32d 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BITCOINUNITS_H
#define BITCOIN_QT_BITCOINUNITS_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractListModel>
#include <QString>
diff --git a/src/qt/callback.h b/src/qt/callback.h
index a8b593a652..da6b0c4c2e 100644
--- a/src/qt/callback.h
+++ b/src/qt/callback.h
@@ -16,7 +16,7 @@ class FunctionCallback : public Callback
F f;
public:
- FunctionCallback(F f_) : f(std::move(f_)) {}
+ explicit FunctionCallback(F f_) : f(std::move(f_)) {}
~FunctionCallback() override {}
void call() override { f(this); }
};
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 52ce11cefd..78174b90a1 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "clientmodel.h"
-
-#include "bantablemodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "peertablemodel.h"
-
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "clientversion.h"
-#include "validation.h"
-#include "net.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "warnings.h"
+#include <qt/clientmodel.h>
+
+#include <qt/bantablemodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/peertablemodel.h>
+
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <clientversion.h>
+#include <validation.h>
+#include <net.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <warnings.h>
#include <stdint.h>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index f3ee0fbe39..49f4e74a9f 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -2,23 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coincontroldialog.h"
-#include "ui_coincontroldialog.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "txmempool.h"
-#include "walletmodel.h"
-
-#include "wallet/coincontrol.h"
-#include "init.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "validation.h" // For mempool
-#include "wallet/wallet.h"
+#include <qt/coincontroldialog.h>
+#include <qt/forms/ui_coincontroldialog.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <txmempool.h>
+#include <qt/walletmodel.h>
+
+#include <wallet/coincontrol.h>
+#include <init.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <validation.h> // For mempool
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
#include <QApplication>
#include <QCheckBox>
@@ -27,9 +28,7 @@
#include <QFlags>
#include <QIcon>
#include <QSettings>
-#include <QString>
#include <QTreeWidget>
-#include <QTreeWidgetItem>
QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
@@ -510,7 +509,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nPayFee = GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
if (nPayAmount > 0)
{
@@ -581,7 +580,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
- double dFeeVary = (double)nPayFee / nBytes;
+ double dFeeVary = (nBytes != 0) ? (double)nPayFee / nBytes : 0;
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
@@ -659,7 +658,7 @@ void CoinControlDialog::updateView()
QString sAddress = "";
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
{
- sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
+ sAddress = QString::fromStdString(EncodeDestination(outputAddress));
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 99a9f893ff..51b0a42907 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_COINCONTROLDIALOG_H
#define BITCOIN_QT_COINCONTROLDIALOG_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractButton>
#include <QAction>
@@ -30,9 +30,9 @@ namespace Ui {
class CCoinControlWidgetItem : public QTreeWidgetItem
{
public:
- CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
- CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
- CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
+ explicit CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
bool operator<(const QTreeWidgetItem &other) const;
};
diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp
index 88510b6168..b628824793 100644
--- a/src/qt/coincontroltreewidget.cpp
+++ b/src/qt/coincontroltreewidget.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coincontroltreewidget.h"
-#include "coincontroldialog.h"
+#include <qt/coincontroltreewidget.h>
+#include <qt/coincontroldialog.h>
CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) :
QTreeWidget(parent)
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index df59927782..702757147b 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "csvmodelwriter.h"
+#include <qt/csvmodelwriter.h>
#include <QAbstractItemModel>
#include <QFile>
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index bb03c12f2d..0437f81a7e 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "editaddressdialog.h"
-#include "ui_editaddressdialog.h"
+#include <qt/editaddressdialog.h>
+#include <qt/forms/ui_editaddressdialog.h>
-#include "addresstablemodel.h"
-#include "guiutil.h"
+#include <qt/addresstablemodel.h>
+#include <qt/guiutil.h>
#include <QDataWidgetMapper>
#include <QMessageBox>
diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
index a2105ecd0a..69803989cd 100644
--- a/src/qt/forms/askpassphrasedialog.ui
+++ b/src/qt/forms/askpassphrasedialog.ui
@@ -93,6 +93,13 @@
</widget>
</item>
<item row="3" column="1">
+ <widget class="QCheckBox" name="toggleShowPasswordButton">
+ <property name="text">
+ <string>Show password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
<widget class="QLabel" name="capsLabel">
<property name="font">
<font>
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index 1ea00eb5c3..d1237ad283 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -487,7 +487,7 @@
<customwidget>
<class>CoinControlTreeWidget</class>
<extends>QTreeWidget</extends>
- <header>coincontroltreewidget.h</header>
+ <header>qt/coincontroltreewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 093e644bdc..bba822882e 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1424,7 +1424,7 @@
<customwidget>
<class>TrafficGraphWidget</class>
<extends>QWidget</extends>
- <header>trafficgraphwidget.h</header>
+ <header>qt/trafficgraphwidget.h</header>
<container>1</container>
<slots>
<slot>clear()</slot>
diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui
index c1aea36338..e968271107 100644
--- a/src/qt/forms/editaddressdialog.ui
+++ b/src/qt/forms/editaddressdialog.ui
@@ -71,7 +71,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui
index 65a7a6c77e..fdc52dc455 100644
--- a/src/qt/forms/modaloverlay.ui
+++ b/src/qt/forms/modaloverlay.ui
@@ -367,7 +367,7 @@ QLabel { color: rgb(40,40,40); }</string>
<customwidget>
<class>ModalOverlay</class>
<extends>QWidget</extends>
- <header>modaloverlay.h</header>
+ <header>qt/modaloverlay.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui
index 7fce858bd2..0e1048bc07 100644
--- a/src/qt/forms/openuridialog.ui
+++ b/src/qt/forms/openuridialog.ui
@@ -77,7 +77,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 14078b9ee8..a3721991ee 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -199,10 +199,10 @@
<item>
<widget class="QCheckBox" name="allowIncoming">
<property name="toolTip">
- <string>Accept connections from outside</string>
+ <string>Accept connections from outside.</string>
</property>
<property name="text">
- <string>Allow incoming connections</string>
+ <string>Allow incomin&amp;g connections</string>
</property>
</widget>
</item>
@@ -399,7 +399,7 @@
<string>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</string>
</property>
<property name="text">
- <string>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</string>
+ <string>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</string>
</property>
</widget>
</item>
@@ -507,10 +507,10 @@
<item>
<widget class="QCheckBox" name="hideTrayIcon">
<property name="toolTip">
- <string>&amp;Hide the icon from the system tray.</string>
+ <string>Hide the icon from the system tray.</string>
</property>
<property name="text">
- <string>Hide tray icon</string>
+ <string>&amp;Hide tray icon</string>
</property>
</widget>
</item>
@@ -610,7 +610,7 @@
<string>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</string>
</property>
<property name="text">
- <string>Third party transaction URLs</string>
+ <string>&amp;Third party transaction URLs</string>
</property>
<property name="buddy">
<cstring>thirdPartyTxUrls</cstring>
@@ -824,12 +824,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
- <header>qvaluecombobox.h</header>
+ <header>qt/qvaluecombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 03fcb2fb50..58f030ebf0 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -28,23 +28,6 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
- <item row="7" column="2">
- <widget class="QCheckBox" name="reuseAddress">
- <property name="toolTip">
- <string>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</string>
- </property>
- <property name="text">
- <string>R&amp;euse an existing receiving address (not recommended)</string>
- </property>
- </widget>
- </item>
- <item row="7" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
<item row="6" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
@@ -127,7 +110,7 @@
</property>
</widget>
</item>
- <item row="8" column="2">
+ <item row="7" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="receiveButton">
@@ -184,7 +167,7 @@
</item>
</layout>
</item>
- <item row="8" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string/>
@@ -316,7 +299,7 @@
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
</customwidgets>
@@ -324,7 +307,6 @@
<tabstop>reqLabel</tabstop>
<tabstop>reqAmount</tabstop>
<tabstop>reqMessage</tabstop>
- <tabstop>reuseAddress</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>recentRequestsView</tabstop>
diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui
index 4163f4189c..dbe966b241 100644
--- a/src/qt/forms/receiverequestdialog.ui
+++ b/src/qt/forms/receiverequestdialog.ui
@@ -127,7 +127,7 @@
<customwidget>
<class>QRImageWidget</class>
<extends>QLabel</extends>
- <header>receiverequestdialog.h</header>
+ <header>qt/receiverequestdialog.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 1e2f2302b9..c6fd708cdf 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -846,19 +846,13 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayoutFee13">
<item>
- <widget class="QRadioButton" name="radioCustomPerKilobyte">
+ <widget class="QLabel" name="labelCustomPerKilobyte">
<property name="toolTip">
<string>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</string>
</property>
<property name="text">
<string>per kilobyte</string>
</property>
- <property name="checked">
- <bool>true</bool>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">groupCustomFee</string>
- </attribute>
</widget>
</item>
<item>
@@ -1114,10 +1108,10 @@
<item>
<widget class="QCheckBox" name="optInRBF">
<property name="text">
- <string>Request Replace-By-Fee</string>
+ <string>Allow increasing 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>
+ <string>This allows you to increase the fee later if the transaction takes a long time to confirm. This will also cause the recommended fee to be lower. ("Replace-By-Fee", BIP 125)</string>
</property>
</widget>
</item>
@@ -1270,12 +1264,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
</customwidgets>
@@ -1285,6 +1279,5 @@
<connections/>
<buttongroups>
<buttongroup name="groupFee"/>
- <buttongroup name="groupCustomFee"/>
</buttongroups>
</ui>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index df06f36833..3c699abc6a 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -163,7 +163,7 @@
</widget>
</item>
<item row="2" column="1">
- <layout class="QHBoxLayout" name="horizontalLayoutAmount" stretch="0,1">
+ <layout class="QHBoxLayout" name="horizontalLayoutAmount" stretch="0,1,0">
<item>
<widget class="BitcoinAmountField" name="payAmount"/>
</item>
@@ -177,6 +177,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QPushButton" name="useAvailableBalanceButton">
+ <property name="text">
+ <string>Use available balance</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item row="3" column="0">
@@ -1248,12 +1255,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
</customwidget>
</customwidgets>
<tabstops>
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
index 92f6430c51..c9ddd757c1 100644
--- a/src/qt/forms/signverifymessagedialog.ui
+++ b/src/qt/forms/signverifymessagedialog.ui
@@ -380,7 +380,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index f3c5daebec..eb5d3304af 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -2,21 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "guiutil.h"
-
-#include "bitcoinaddressvalidator.h"
-#include "bitcoinunits.h"
-#include "qvalidatedlineedit.h"
-#include "walletmodel.h"
-
-#include "fs.h"
-#include "primitives/transaction.h"
-#include "init.h"
-#include "policy/policy.h"
-#include "protocol.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
+#include <qt/guiutil.h>
+
+#include <qt/bitcoinaddressvalidator.h>
+#include <qt/bitcoinunits.h>
+#include <qt/qvalidatedlineedit.h>
+#include <qt/walletmodel.h>
+
+#include <primitives/transaction.h>
+#include <init.h>
+#include <policy/policy.h>
+#include <protocol.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -31,9 +30,9 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
-#include "shellapi.h"
-#include "shlobj.h"
-#include "shlwapi.h"
+#include <shellapi.h>
+#include <shlobj.h>
+#include <shlwapi.h>
#endif
#include <boost/scoped_array.hpp>
@@ -112,8 +111,9 @@ static std::string DummyAddress(const CChainParams &params)
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
- if (!CBitcoinAddress(s).IsValid())
+ if (!IsValidDestinationString(s)) {
return s;
+ }
sourcedata[sourcedata.size()-1] += 1;
}
return "";
@@ -248,7 +248,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
bool isDust(const QString& address, const CAmount& amount)
{
- CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
+ CTxDestination dest = DecodeDestination(address.toStdString());
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
return IsDust(txOut, ::dustRelayFee);
@@ -743,9 +743,10 @@ bool SetStartOnSystemStartup(bool fAutoStart)
else
{
char pszExePath[MAX_PATH+1];
- memset(pszExePath, 0, sizeof(pszExePath));
- if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+ ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
+ if (r == -1)
return false;
+ pszExePath[r] = '\0';
fs::create_directories(GetAutostartDir());
@@ -780,47 +781,64 @@ bool SetStartOnSystemStartup(bool fAutoStart)
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
{
- // loop through the list of startup items and try to find the bitcoin app
CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr);
+ if (listSnapshot == nullptr) {
+ return nullptr;
+ }
+
+ // loop through the list of startup items and try to find the bitcoin app
for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
CFURLRef currentItemURL = nullptr;
#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100
- if(&LSSharedFileListItemCopyResolvedURL)
- currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr);
+ if(&LSSharedFileListItemCopyResolvedURL)
+ currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr);
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100
- else
- LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
+ else
+ LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
#endif
#else
- LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
+ LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
#endif
- if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
- // found
- CFRelease(currentItemURL);
- return item;
- }
if(currentItemURL) {
+ if (CFEqual(currentItemURL, findUrl)) {
+ // found
+ CFRelease(listSnapshot);
+ CFRelease(currentItemURL);
+ return item;
+ }
CFRelease(currentItemURL);
}
}
+
+ CFRelease(listSnapshot);
return nullptr;
}
bool GetStartOnSystemStartup()
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ if (bitcoinAppUrl == nullptr) {
+ return false;
+ }
+
LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
+
+ CFRelease(bitcoinAppUrl);
return !!foundItem; // return boolified object
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ if (bitcoinAppUrl == nullptr) {
+ return false;
+ }
+
LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
@@ -832,6 +850,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// remove item
LSSharedFileListItemRemove(loginItems, foundItem);
}
+
+ CFRelease(bitcoinAppUrl);
return true;
}
#pragma GCC diagnostic pop
@@ -842,32 +862,6 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
-void saveWindowGeometry(const QString& strSetting, QWidget *parent)
-{
- QSettings settings;
- settings.setValue(strSetting + "Pos", parent->pos());
- settings.setValue(strSetting + "Size", parent->size());
-}
-
-void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent)
-{
- QSettings settings;
- QPoint pos = settings.value(strSetting + "Pos").toPoint();
- QSize size = settings.value(strSetting + "Size", defaultSize).toSize();
-
- parent->resize(size);
- parent->move(pos);
-
- if ((!pos.x() && !pos.y()) || (QApplication::desktop()->screenNumber(parent) == -1))
- {
- QRect screen = QApplication::desktop()->screenGeometry();
- QPoint defaultPos((screen.width() - defaultSize.width()) / 2,
- (screen.height() - defaultSize.height()) / 2);
- parent->resize(defaultSize);
- parent->move(defaultPos);
- }
-}
-
void setClipboard(const QString& str)
{
QApplication::clipboard()->setText(str, QClipboard::Clipboard);
@@ -989,6 +983,18 @@ QString formatNiceTimeOffset(qint64 secs)
return timeBehindText;
}
+QString formatBytes(uint64_t bytes)
+{
+ if(bytes < 1024)
+ return QString(QObject::tr("%1 B")).arg(bytes);
+ if(bytes < 1024 * 1024)
+ return QString(QObject::tr("%1 KB")).arg(bytes / 1024);
+ if(bytes < 1024 * 1024 * 1024)
+ return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024);
+
+ return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
+}
+
void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
{
Q_EMIT clicked(event->pos());
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index d6aa8c4ea6..d0ab491952 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_GUIUTIL_H
#define BITCOIN_QT_GUIUTIL_H
-#include "amount.h"
-#include "fs.h"
+#include <amount.h>
+#include <fs.h>
#include <QEvent>
#include <QHeaderView>
@@ -179,11 +179,6 @@ namespace GUIUtil
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
- /** Save window size and position */
- void saveWindowGeometry(const QString& strSetting, QWidget *parent);
- /** Restore window size and position */
- void restoreWindowGeometry(const QString& strSetting, const QSize &defaultSizeIn, QWidget *parent);
-
/* Convert QString to OS specific boost path through UTF-8 */
fs::path qstringToBoostPath(const QString &path);
@@ -204,6 +199,8 @@ namespace GUIUtil
QString formatNiceTimeOffset(qint64 secs);
+ QString formatBytes(uint64_t bytes);
+
class ClickableLabel : public QLabel
{
Q_OBJECT
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 72809942f1..7f8a8394e6 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -3,16 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "fs.h"
-#include "intro.h"
-#include "ui_intro.h"
+#include <fs.h>
+#include <qt/intro.h>
+#include <qt/forms/ui_intro.h>
-#include "guiutil.h"
+#include <qt/guiutil.h>
-#include "util.h"
+#include <util.h>
#include <QFileDialog>
#include <QSettings>
@@ -43,7 +43,7 @@ class FreespaceChecker : public QObject
Q_OBJECT
public:
- FreespaceChecker(Intro *intro);
+ explicit FreespaceChecker(Intro *intro);
enum Status {
ST_OK,
@@ -60,7 +60,7 @@ private:
Intro *intro;
};
-#include "intro.moc"
+#include <qt/intro.moc>
FreespaceChecker::FreespaceChecker(Intro *_intro)
{
@@ -214,7 +214,10 @@ bool Intro::pickDataDirectory()
}
dataDir = intro.getDataDirectory();
try {
- TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir));
+ if (TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir))) {
+ // If a new data directory has been created, make wallets subdirectory too
+ TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets");
+ }
break;
} catch (const fs::filesystem_error&) {
QMessageBox::critical(0, tr(PACKAGE_NAME),
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index a41d39d51e..9e7de0f98f 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -18,7 +18,7 @@
extern void qt_mac_set_dock_menu(QMenu *);
#endif
-static MacDockIconHandler *s_instance = NULL;
+static MacDockIconHandler *s_instance = nullptr;
bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self)
@@ -34,7 +34,7 @@ void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication");
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));
- if (appInst != NULL) {
+ if (appInst != nullptr) {
id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
@@ -53,7 +53,7 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
setupDockClickHandler();
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
#if QT_VERSION < 0x050000
qt_mac_set_dock_menu(this->m_dockMenu);
#elif QT_VERSION >= 0x050200
@@ -69,7 +69,7 @@ void MacDockIconHandler::setMainWindow(QMainWindow *window) {
MacDockIconHandler::~MacDockIconHandler()
{
delete this->m_dummyWidget;
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
}
QMenu *MacDockIconHandler::dockMenu()
diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h
index d4749b3d5f..3a005c3c46 100644
--- a/src/qt/macnotificationhandler.h
+++ b/src/qt/macnotificationhandler.h
@@ -7,20 +7,17 @@
#include <QObject>
-/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl).
+/** Macintosh-specific notification handler (supports UserNotificationCenter).
*/
class MacNotificationHandler : public QObject
{
Q_OBJECT
public:
- /** shows a 10.8+ UserNotification in the UserNotificationCenter
+ /** shows a macOS 10.8+ UserNotification in the UserNotificationCenter
*/
void showNotification(const QString &title, const QString &text);
- /** executes AppleScript */
- void sendAppleScript(const QString &script);
-
/** check if OS can handle UserNotifications */
bool hasUserNotificationCenterSupport(void);
static MacNotificationHandler *instance();
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
index dd3f622818..1b16c5f524 100644
--- a/src/qt/macnotificationhandler.mm
+++ b/src/qt/macnotificationhandler.mm
@@ -47,20 +47,6 @@ void MacNotificationHandler::showNotification(const QString &title, const QStrin
}
}
-// sendAppleScript just take a QString and executes it as apple script
-void MacNotificationHandler::sendAppleScript(const QString &script)
-{
- QByteArray utf8 = script.toUtf8();
- char* cString = (char *)utf8.constData();
- NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString];
-
- NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple];
- NSDictionary *err = nil;
- [as executeAndReturnError:&err];
- [as release];
- [scriptApple release];
-}
-
bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
{
Class possibleClass = NSClassFromString(@"NSUserNotificationCenter");
@@ -75,7 +61,7 @@ bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
MacNotificationHandler *MacNotificationHandler::instance()
{
- static MacNotificationHandler *s_instance = NULL;
+ static MacNotificationHandler *s_instance = nullptr;
if (!s_instance) {
s_instance = new MacNotificationHandler();
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index a83f285034..b707b0dda9 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "modaloverlay.h"
-#include "ui_modaloverlay.h"
+#include <qt/modaloverlay.h>
+#include <qt/forms/ui_modaloverlay.h>
-#include "guiutil.h"
+#include <qt/guiutil.h>
-#include "chainparams.h"
+#include <chainparams.h>
#include <QResizeEvent>
#include <QPropertyAnimation>
@@ -82,36 +82,38 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
// show progress speed if we have more then one sample
- if (blockProcessTime.size() >= 2)
- {
- double progressStart = blockProcessTime[0].second;
+ if (blockProcessTime.size() >= 2) {
double progressDelta = 0;
double progressPerHour = 0;
qint64 timeDelta = 0;
qint64 remainingMSecs = 0;
double remainingProgress = 1.0 - nVerificationProgress;
- for (int i = 1; i < blockProcessTime.size(); i++)
- {
+ for (int i = 1; i < blockProcessTime.size(); i++) {
QPair<qint64, double> sample = blockProcessTime[i];
// take first sample after 500 seconds or last available one
if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
- progressDelta = progressStart-sample.second;
+ progressDelta = blockProcessTime[0].second - sample.second;
timeDelta = blockProcessTime[0].first - sample.first;
- progressPerHour = progressDelta/(double)timeDelta*1000*3600;
- remainingMSecs = remainingProgress / progressDelta * timeDelta;
+ progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
+ remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
break;
}
}
// show progress increase per hour
- ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%");
+ ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
// show expected remaining time
- ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0));
+ if(remainingMSecs >= 0) {
+ ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
+ } else {
+ ui->expectedTimeLeft->setText(QObject::tr("unknown"));
+ }
static const int MAX_SAMPLES = 5000;
- if (blockProcessTime.count() > MAX_SAMPLES)
- blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES);
+ if (blockProcessTime.count() > MAX_SAMPLES) {
+ blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
+ }
}
// show the last block date
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 21ccdbd839..cda23f9540 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -32,7 +32,7 @@ public Q_SLOTS:
// will show or hide the modal layer
void showHide(bool hide = false, bool userRequested = false);
void closeClicked();
- bool isLayerVisible() { return layerIsVisible; }
+ bool isLayerVisible() const { return layerIsVisible; }
protected:
bool eventFilter(QObject * obj, QEvent * ev);
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 93092501c9..42ae3ae566 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "networkstyle.h"
+#include <qt/networkstyle.h>
-#include "guiconstants.h"
+#include <qt/guiconstants.h>
#include <QApplication>
@@ -44,7 +44,7 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift,
// loop through pixels
for(int x=0;x<img.width();x++)
{
- // preserve alpha because QColor::getHsl doesen't return the alpha value
+ // preserve alpha because QColor::getHsl doesn't return the alpha value
a = qAlpha(scL[x]);
QColor col(scL[x]);
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 8718929c6a..f4383bf679 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -2,11 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "notificator.h"
+#include <qt/notificator.h>
#include <QApplication>
#include <QByteArray>
-#include <QIcon>
#include <QImageWriter>
#include <QMessageBox>
#include <QMetaType>
@@ -24,7 +23,7 @@
// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
-#include "macnotificationhandler.h"
+#include <qt/macnotificationhandler.h>
#endif
@@ -60,22 +59,6 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon
if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
mode = UserNotificationCenter;
}
- else {
- // Check if Growl is installed (based on Qt's tray icon implementation)
- CFURLRef cfurl;
- OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
- if (status != kLSApplicationNotFoundErr) {
- CFBundleRef bundle = CFBundleCreate(0, cfurl);
- if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
- if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
- mode = Growl13;
- else
- mode = Growl12;
- }
- CFRelease(cfurl);
- CFRelease(bundle);
- }
- }
#endif
}
@@ -93,7 +76,7 @@ class FreedesktopImage
{
public:
FreedesktopImage() {}
- FreedesktopImage(const QImage &img);
+ explicit FreedesktopImage(const QImage &img);
static int metaType();
@@ -241,52 +224,6 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString &
// Based on Qt's tray icon implementation
#ifdef Q_OS_MAC
-void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon)
-{
- const QString script(
- "tell application \"%5\"\n"
- " set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all)
- " set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled)
- " register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl
- " notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification
- "end tell"
- );
-
- QString notificationApp(QApplication::applicationName());
- if (notificationApp.isEmpty())
- notificationApp = "Application";
-
- QPixmap notificationIconPixmap;
- if (icon.isNull()) { // If no icon specified, set icon based on class
- QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
- switch (cls)
- {
- case Information: sicon = QStyle::SP_MessageBoxInformation; break;
- case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
- case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
- }
- notificationIconPixmap = QApplication::style()->standardPixmap(sicon);
- }
- else {
- QSize size = icon.actualSize(QSize(48, 48));
- notificationIconPixmap = icon.pixmap(size);
- }
-
- QString notificationIcon;
- QTemporaryFile notificationIconFile;
- if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
- QImageWriter writer(&notificationIconFile, "PNG");
- if (writer.write(notificationIconPixmap.toImage()))
- notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName());
- }
-
- QString quotedTitle(title), quotedText(text);
- quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
- quotedText.replace("\\", "\\\\").replace("\"", "\\");
- QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
- MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
-}
-
void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
// icon is not supported by the user notification center yet. OSX will use the app icon.
MacNotificationHandler::instance()->showNotification(title, text);
@@ -310,10 +247,6 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c
case UserNotificationCenter:
notifyMacUserNotificationCenter(cls, title, text, icon);
break;
- case Growl12:
- case Growl13:
- notifyGrowl(cls, title, text, icon);
- break;
#endif
default:
if(cls == Critical)
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index f92b791d4a..ef6f5c7ec5 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -6,7 +6,7 @@
#define BITCOIN_QT_NOTIFICATOR_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <QIcon>
@@ -58,8 +58,6 @@ private:
None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
Freedesktop, /**< Use DBus org.freedesktop.Notifications */
QSystemTray, /**< Use QSystemTray::showMessage */
- Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
- Growl13, /**< Use the Growl 1.3 notification system (Mac only) */
UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
};
QString programName;
@@ -72,7 +70,6 @@ private:
#endif
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#ifdef Q_OS_MAC
- void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon);
void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon);
#endif
};
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 3ee656d470..40671922f4 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "openuridialog.h"
-#include "ui_openuridialog.h"
+#include <qt/openuridialog.h>
+#include <qt/forms/ui_openuridialog.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
#include <QUrl>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index b80b6541dd..a0f78d5ead 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -3,23 +3,19 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "optionsdialog.h"
-#include "ui_optionsdialog.h"
+#include <qt/optionsdialog.h>
+#include <qt/forms/ui_optionsdialog.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "validation.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
-#include "netbase.h"
-#include "txdb.h" // for -dbcache defaults
-
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h" // for CWallet::GetRequiredFee()
-#endif
+#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
+#include <netbase.h>
+#include <txdb.h> // for -dbcache defaults
#include <QDataWidgetMapper>
#include <QDir>
@@ -80,6 +76,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME)));
+ ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME)));
+
ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
for (const QString &langStr : translations.entryList())
@@ -340,7 +338,7 @@ QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) cons
{
Q_UNUSED(pos);
// Validate the proxy
- CService serv(LookupNumeric(input.toStdString().c_str(), 9050));
+ CService serv(LookupNumeric(input.toStdString().c_str(), DEFAULT_GUI_PROXY_PORT));
proxyType addrProxy = proxyType(serv, true);
if (addrProxy.IsValid())
return QValidator::Acceptable;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 77efef3e3c..c9e4f517c7 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -3,31 +3,32 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "optionsmodel.h"
+#include <qt/optionsmodel.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
-#include "amount.h"
-#include "init.h"
-#include "validation.h" // For DEFAULT_SCRIPTCHECK_THREADS
-#include "net.h"
-#include "netbase.h"
-#include "txdb.h" // for -dbcache defaults
-#include "intro.h"
+#include <init.h>
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <net.h>
+#include <netbase.h>
+#include <txdb.h> // for -dbcache defaults
+#include <qt/intro.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
#endif
#include <QNetworkProxy>
#include <QSettings>
#include <QStringList>
+const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
+
OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
QAbstractListModel(parent)
{
@@ -125,7 +126,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseProxy"))
settings.setValue("fUseProxy", false);
if (!settings.contains("addrProxy"))
- settings.setValue("addrProxy", "127.0.0.1:9050");
+ settings.setValue("addrProxy", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
@@ -135,7 +136,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseSeparateProxyTor"))
settings.setValue("fUseSeparateProxyTor", false);
if (!settings.contains("addrSeparateProxyTor"))
- settings.setValue("addrSeparateProxyTor", "127.0.0.1:9050");
+ settings.setValue("addrSeparateProxyTor", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
if (settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
addOverriddenOption("-onion");
@@ -151,10 +152,32 @@ void OptionsModel::Init(bool resetSettings)
language = settings.value("language").toString();
}
+/** Helper function to copy contents from one QSettings to another.
+ * By using allKeys this also covers nested settings in a hierarchy.
+ */
+static void CopySettings(QSettings& dst, const QSettings& src)
+{
+ for (const QString& key : src.allKeys()) {
+ dst.setValue(key, src.value(key));
+ }
+}
+
+/** Back up a QSettings to an ini-formatted file. */
+static void BackupSettings(const fs::path& filename, const QSettings& src)
+{
+ qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
+ QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
+ dst.clear();
+ CopySettings(dst, src);
+}
+
void OptionsModel::Reset()
{
QSettings settings;
+ // Backup old settings to chain-specific datadir for troubleshooting
+ BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
+
// Save the strDataDir setting
QString dataDir = Intro::getDefaultDataDirectory();
dataDir = settings.value("strDataDir", dataDir).toString();
@@ -178,6 +201,33 @@ int OptionsModel::rowCount(const QModelIndex & parent) const
return OptionIDRowCount;
}
+struct ProxySetting {
+ bool is_set;
+ QString ip;
+ QString port;
+};
+
+static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
+{
+ static const ProxySetting default_val = {false, DEFAULT_GUI_PROXY_HOST, QString("%1").arg(DEFAULT_GUI_PROXY_PORT)};
+ // Handle the case that the setting is not set at all
+ if (!settings.contains(name)) {
+ return default_val;
+ }
+ // contains IP at index 0 and port at index 1
+ QStringList ip_port = settings.value(name).toString().split(":", QString::SkipEmptyParts);
+ if (ip_port.size() == 2) {
+ return {true, ip_port.at(0), ip_port.at(1)};
+ } else { // Invalid: return default
+ return default_val;
+ }
+}
+
+static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port)
+{
+ settings.setValue(name, ip_port.ip + ":" + ip_port.port);
+}
+
// read QSettings values and return them
QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
@@ -204,30 +254,18 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
// default proxy
case ProxyUse:
return settings.value("fUseProxy", false);
- case ProxyIP: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(0);
- }
- case ProxyPort: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(1);
- }
+ case ProxyIP:
+ return GetProxySetting(settings, "addrProxy").ip;
+ case ProxyPort:
+ return GetProxySetting(settings, "addrProxy").port;
// separate Tor proxy
case ProxyUseTor:
return settings.value("fUseSeparateProxyTor", false);
- case ProxyIPTor: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(0);
- }
- case ProxyPortTor: {
- // contains IP at index 0 and port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- return strlIpPort.at(1);
- }
+ case ProxyIPTor:
+ return GetProxySetting(settings, "addrSeparateProxyTor").ip;
+ case ProxyPortTor:
+ return GetProxySetting(settings, "addrSeparateProxyTor").port;
#ifdef ENABLE_WALLET
case SpendZeroConfChange:
@@ -292,25 +330,19 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
break;
case ProxyIP: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed IP
- if (!settings.contains("addrProxy") || strlIpPort.at(0) != value.toString()) {
- // construct new value from new IP and current port
- QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
- settings.setValue("addrProxy", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrProxy");
+ if (!ip_port.is_set || ip_port.ip != value.toString()) {
+ ip_port.ip = value.toString();
+ SetProxySetting(settings, "addrProxy", ip_port);
setRestartRequired(true);
}
}
break;
case ProxyPort: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed port
- if (!settings.contains("addrProxy") || strlIpPort.at(1) != value.toString()) {
- // construct new value from current IP and new port
- QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
- settings.setValue("addrProxy", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrProxy");
+ if (!ip_port.is_set || ip_port.port != value.toString()) {
+ ip_port.port = value.toString();
+ SetProxySetting(settings, "addrProxy", ip_port);
setRestartRequired(true);
}
}
@@ -324,25 +356,19 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
break;
case ProxyIPTor: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed IP
- if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(0) != value.toString()) {
- // construct new value from new IP and current port
- QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
- settings.setValue("addrSeparateProxyTor", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrSeparateProxyTor");
+ if (!ip_port.is_set || ip_port.ip != value.toString()) {
+ ip_port.ip = value.toString();
+ SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
setRestartRequired(true);
}
}
break;
case ProxyPortTor: {
- // contains current IP at index 0 and current port at index 1
- QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
- // if that key doesn't exist or has a changed port
- if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(1) != value.toString()) {
- // construct new value from current IP and new port
- QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
- settings.setValue("addrSeparateProxyTor", strNewValue);
+ auto ip_port = GetProxySetting(settings, "addrSeparateProxyTor");
+ if (!ip_port.is_set || ip_port.port != value.toString()) {
+ ip_port.port = value.toString();
+ SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
setRestartRequired(true);
}
}
@@ -441,7 +467,7 @@ void OptionsModel::setRestartRequired(bool fRequired)
return settings.setValue("fRestartRequired", fRequired);
}
-bool OptionsModel::isRestartRequired()
+bool OptionsModel::isRestartRequired() const
{
QSettings settings;
return settings.value("fRestartRequired", false).toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 78529fbdcc..f8782dd204 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_OPTIONSMODEL_H
#define BITCOIN_QT_OPTIONSMODEL_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractListModel>
@@ -13,6 +13,9 @@ QT_BEGIN_NAMESPACE
class QNetworkProxy;
QT_END_NAMESPACE
+extern const char *DEFAULT_GUI_PROXY_HOST;
+static constexpr unsigned short DEFAULT_GUI_PROXY_PORT = 9050;
+
/** Interface from Qt to configuration data structure for Bitcoin client.
To Qt, the options are presented as a list with the different options
laid out vertically.
@@ -59,18 +62,18 @@ public:
void setDisplayUnit(const QVariant &value);
/* Explicit getters */
- bool getHideTrayIcon() { return fHideTrayIcon; }
- bool getMinimizeToTray() { return fMinimizeToTray; }
- bool getMinimizeOnClose() { return fMinimizeOnClose; }
- int getDisplayUnit() { return nDisplayUnit; }
- QString getThirdPartyTxUrls() { return strThirdPartyTxUrls; }
+ bool getHideTrayIcon() const { return fHideTrayIcon; }
+ bool getMinimizeToTray() const { return fMinimizeToTray; }
+ bool getMinimizeOnClose() const { return fMinimizeOnClose; }
+ int getDisplayUnit() const { return nDisplayUnit; }
+ QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; }
bool getProxySettings(QNetworkProxy& proxy) const;
- bool getCoinControlFeatures() { return fCoinControlFeatures; }
+ bool getCoinControlFeatures() const { return fCoinControlFeatures; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
/* Restart flag helper */
void setRestartRequired(bool fRequired);
- bool isRestartRequired();
+ bool isRestartRequired() const;
private:
/* Qt-only settings */
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index ba344f4dbf..7818607d30 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "overviewpage.h"
-#include "ui_overviewpage.h"
-
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "transactionfilterproxy.h"
-#include "transactiontablemodel.h"
-#include "walletmodel.h"
+#include <qt/overviewpage.h>
+#include <qt/forms/ui_overviewpage.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/transactionfilterproxy.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/walletmodel.h>
#include <QAbstractItemDelegate>
#include <QPainter>
@@ -25,7 +25,7 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
+ explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
@@ -106,7 +106,7 @@ public:
const PlatformStyle *platformStyle;
};
-#include "overviewpage.moc"
+#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index d76b651ce6..1e09d907b0 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_OVERVIEWPAGE_H
#define BITCOIN_QT_OVERVIEWPAGE_H
-#include "amount.h"
+#include <amount.h>
#include <QWidget>
#include <memory>
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 0a5cb98668..4503728882 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -7,9 +7,9 @@
// with some extra methods
//
-#include "paymentrequestplus.h"
+#include <qt/paymentrequestplus.h>
-#include "util.h"
+#include <util.h>
#include <stdexcept>
@@ -22,7 +22,7 @@
class SSLVerifyError : public std::runtime_error
{
public:
- SSLVerifyError(std::string err) : std::runtime_error(err) { }
+ explicit SSLVerifyError(std::string err) : std::runtime_error(err) { }
};
bool PaymentRequestPlus::parse(const QByteArray& data)
@@ -194,8 +194,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what();
}
- if (website)
- delete[] website;
+ delete[] website;
X509_STORE_CTX_free(store_ctx);
for (unsigned int i = 0; i < certs.size(); i++)
X509_free(certs[i]);
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index a2fea3fdc6..e1388f2b5d 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -7,10 +7,10 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#include "paymentrequest.pb.h"
+#include <qt/paymentrequest.pb.h>
#pragma GCC diagnostic pop
-#include "base58.h"
+#include <base58.h>
#include <openssl/x509.h>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 67fe320185..510a3783ae 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentserver.h"
+#include <qt/paymentserver.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "base58.h"
-#include "chainparams.h"
-#include "policy/policy.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <chainparams.h>
+#include <policy/policy.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <wallet/wallet.h>
#include <cstdlib>
@@ -218,17 +218,15 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
SendCoinsRecipient r;
if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
- CBitcoinAddress address(r.address.toStdString());
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
- if (address.IsValid(*tempChainParams))
- {
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::MAIN);
- }
- else {
+ } else {
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
- if (address.IsValid(*tempChainParams))
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::TESTNET);
+ }
}
}
}
@@ -364,8 +362,7 @@ void PaymentServer::initNetManager()
{
if (!optionsModel)
return;
- if (netManager != nullptr)
- delete netManager;
+ delete netManager;
// netManager is used to fetch paymentrequests given in bitcoin: URIs
netManager = new QNetworkAccessManager(this);
@@ -441,8 +438,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
{
- CBitcoinAddress address(recipient.address.toStdString());
- if (!address.IsValid()) {
+ if (!IsValidDestinationString(recipient.address.toStdString())) {
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
@@ -560,7 +556,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
// Append destination address
- addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
+ addresses.append(QString::fromStdString(EncodeDestination(dest)));
}
else if (!recipient.authenticatedMerchant.isEmpty()) {
// Unauthenticated payment requests to custom bitcoin addresses are not supported
@@ -620,7 +616,7 @@ void PaymentServer::fetchRequest(const QUrl& url)
netManager->get(netRequest);
}
-void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction)
+void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction)
{
const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
if (!details.has_payment_url())
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 2fe6e3e7b1..9adef9743d 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -32,8 +32,8 @@
// sends them to the server.
//
-#include "paymentrequestplus.h"
-#include "walletmodel.h"
+#include <qt/paymentrequestplus.h>
+#include <qt/walletmodel.h>
#include <QObject>
#include <QString>
@@ -72,7 +72,7 @@ public:
static bool ipcSendCommandLine();
// parent should be QApplication object
- PaymentServer(QObject* parent, bool startLocalServer = true);
+ explicit PaymentServer(QObject* parent, bool startLocalServer = true);
~PaymentServer();
// Load root certificate authorities. Pass nullptr (default)
@@ -113,7 +113,7 @@ public Q_SLOTS:
void uiReady();
// Submit Payment message to a merchant, get back PaymentACK:
- void fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction);
+ void fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction);
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 42934f8055..cfafab2c8a 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "peertablemodel.h"
+#include <qt/peertablemodel.h>
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
-#include "validation.h" // for cs_main
-#include "sync.h"
+#include <validation.h> // for cs_main
+#include <sync.h>
#include <QDebug>
#include <QList>
@@ -33,6 +33,10 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
case PeerTableModel::Ping:
return pLeft->dMinPing < pRight->dMinPing;
+ case PeerTableModel::Sent:
+ return pLeft->nSendBytes < pRight->nSendBytes;
+ case PeerTableModel::Received:
+ return pLeft->nRecvBytes < pRight->nRecvBytes;
}
return false;
@@ -114,7 +118,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent),
timer(0)
{
- columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping");
+ columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
priv.reset(new PeerTablePriv());
// default to unsorted
priv->sortColumn = -1;
@@ -173,10 +177,20 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
return QString::fromStdString(rec->nodeStats.cleanSubVer);
case Ping:
return GUIUtil::formatPingTime(rec->nodeStats.dMinPing);
+ case Sent:
+ return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
+ case Received:
+ return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
}
} else if (role == Qt::TextAlignmentRole) {
- if (index.column() == Ping)
- return (QVariant)(Qt::AlignRight | Qt::AlignVCenter);
+ switch (index.column()) {
+ case Ping:
+ case Sent:
+ case Received:
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ default:
+ return QVariant();
+ }
}
return QVariant();
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index cc47b67ec9..e41fe4bb03 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_PEERTABLEMODEL_H
#define BITCOIN_QT_PEERTABLEMODEL_H
-#include "net_processing.h" // For CNodeStateStats
-#include "net.h"
+#include <net_processing.h> // For CNodeStateStats
+#include <net.h>
#include <QAbstractTableModel>
#include <QStringList>
@@ -55,8 +55,10 @@ public:
enum ColumnIndex {
NetNodeId = 0,
Address = 1,
- Subversion = 2,
- Ping = 3
+ Ping = 2,
+ Sent = 3,
+ Received = 4,
+ Subversion = 5
};
/** @name Methods overridden from QAbstractTableModel
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 1f4e1a442f..0e1bd59ada 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -2,16 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "platformstyle.h"
+#include <qt/platformstyle.h>
-#include "guiconstants.h"
+#include <qt/guiconstants.h>
#include <QApplication>
#include <QColor>
-#include <QIcon>
#include <QImage>
#include <QPalette>
-#include <QPixmap>
static const struct {
const char *platformId;
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index 179ecdc8b3..4d6d5891c9 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "qvalidatedlineedit.h"
+#include <qt/qvalidatedlineedit.h>
-#include "bitcoinaddressvalidator.h"
-#include "guiconstants.h"
+#include <qt/bitcoinaddressvalidator.h>
+#include <qt/guiconstants.h>
QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
QLineEdit(parent),
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index a3b9b994ec..af5f6f8fd0 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "qvaluecombobox.h"
+#include <qt/qvaluecombobox.h>
QValueComboBox::QValueComboBox(QWidget *parent) :
QComboBox(parent), role(Qt::UserRole)
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 84f43266e1..e9dcbc0a72 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -2,22 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "receivecoinsdialog.h"
-#include "ui_receivecoinsdialog.h"
-
-#include "addressbookpage.h"
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "receiverequestdialog.h"
-#include "recentrequeststablemodel.h"
-#include "walletmodel.h"
+#include <qt/receivecoinsdialog.h>
+#include <qt/forms/ui_receivecoinsdialog.h>
+
+#include <qt/addressbookpage.h>
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/receiverequestdialog.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/walletmodel.h>
#include <QAction>
#include <QCursor>
-#include <QItemSelection>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
@@ -106,7 +104,6 @@ void ReceiveCoinsDialog::clear()
ui->reqAmount->clear();
ui->reqLabel->setText("");
ui->reqMessage->setText("");
- ui->reuseAddress->setChecked(false);
updateDisplayUnit();
}
@@ -135,25 +132,8 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
QString address;
QString label = ui->reqLabel->text();
- if(ui->reuseAddress->isChecked())
- {
- /* Choose existing receiving address */
- AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
- dlg.setModel(model->getAddressTableModel());
- if(dlg.exec())
- {
- address = dlg.getReturnValue();
- if(label.isEmpty()) /* If no label provided, use the previously used label */
- {
- label = model->getAddressTableModel()->labelForAddress(address);
- }
- } else {
- return;
- }
- } else {
- /* Generate new receiving address */
- address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "");
- }
+ /* Generate new receiving address */
+ address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "");
SendCoinsRecipient info(address, label,
ui->reqAmount->value(), ui->reqMessage->text());
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 385f98565c..3687cca87b 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECEIVECOINSDIALOG_H
#define BITCOIN_QT_RECEIVECOINSDIALOG_H
-#include "guiutil.h"
+#include <qt/guiutil.h>
#include <QDialog>
#include <QHeaderView>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 4aa6375d8a..d30e9b2dca 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -2,14 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "receiverequestdialog.h"
-#include "ui_receiverequestdialog.h"
+#include <qt/receiverequestdialog.h>
+#include <qt/forms/ui_receiverequestdialog.h>
-#include "bitcoinunits.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "walletmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
#include <QClipboard>
#include <QDrag>
@@ -22,7 +21,7 @@
#endif
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h" /* for USE_QRCODE */
+#include <config/bitcoin-config.h> /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 1a9b165237..23b81135e2 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECEIVEREQUESTDIALOG_H
#define BITCOIN_QT_RECEIVEREQUESTDIALOG_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QDialog>
#include <QImage>
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 1c4f7aca86..4d6e401d0d 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "recentrequeststablemodel.h"
+#include <qt/recentrequeststablemodel.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "clientversion.h"
-#include "streams.h"
+#include <clientversion.h>
+#include <streams.h>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 0c02968f92..c88b8c4426 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECENTREQUESTSTABLEMODEL_H
#define BITCOIN_QT_RECENTREQUESTSTABLEMODEL_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QAbstractTableModel>
#include <QStringList>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 3590a98efa..0b90205270 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -3,21 +3,20 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "rpcconsole.h"
-#include "ui_debugwindow.h"
+#include <qt/rpcconsole.h>
+#include <qt/forms/ui_debugwindow.h>
-#include "bantablemodel.h"
-#include "clientmodel.h"
-#include "guiutil.h"
-#include "platformstyle.h"
-#include "chainparams.h"
-#include "netbase.h"
-#include "rpc/server.h"
-#include "rpc/client.h"
-#include "util.h"
+#include <qt/bantablemodel.h>
+#include <qt/clientmodel.h>
+#include <qt/platformstyle.h>
+#include <chainparams.h>
+#include <netbase.h>
+#include <rpc/server.h>
+#include <rpc/client.h>
+#include <util.h>
#include <openssl/crypto.h>
@@ -28,13 +27,13 @@
#include <wallet/wallet.h>
#endif
+#include <QDesktopWidget>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
-#include <QThread>
#include <QTime>
#include <QTimer>
#include <QStringList>
@@ -124,7 +123,7 @@ public:
};
-#include "rpcconsole.moc"
+#include <qt/rpcconsole.moc>
/**
* Split shell command line into a list of arguments and optionally execute the command(s).
@@ -391,11 +390,37 @@ void RPCExecutor::request(const QString &command)
{
std::string result;
std::string executableCommand = command.toStdString() + "\n";
+
+ // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
+ if(executableCommand == "help-console\n")
+ {
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString(("\n"
+ "This console accepts RPC commands using the standard syntax.\n"
+ " example: getblockhash 0\n\n"
+
+ "This console can also accept RPC commands using parenthesized syntax.\n"
+ " example: getblockhash(0)\n\n"
+
+ "Commands may be nested when specified with the parenthesized syntax.\n"
+ " example: getblock(getblockhash(0) 1)\n\n"
+
+ "A space or a comma can be used to delimit arguments for either syntax.\n"
+ " example: getblockhash 0\n"
+ " getblockhash,0\n\n"
+
+ "Named results can be queried with a non-quoted key string in brackets.\n"
+ " example: getblock(getblockhash(0) true)[tx]\n\n"
+
+ "Results without keys can be queried using an integer in brackets.\n"
+ " example: getblock(getblockhash(0),true)[tx][0]\n\n")));
+ return;
+ }
if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand))
{
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
return;
}
+
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
}
catch (UniValue& objError)
@@ -428,7 +453,11 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
consoleFontSize(0)
{
ui->setupUi(this);
- GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));
@@ -466,14 +495,14 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
- QSettings settings;
consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt();
clear();
}
RPCConsole::~RPCConsole()
{
- GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
+ QSettings settings;
+ settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -640,6 +669,7 @@ void RPCConsole::setClientModel(ClientModel *model)
wordList << ("help " + commandList[i]).c_str();
}
+ wordList << "help-console";
wordList.sort();
autoCompleter = new QCompleter(wordList, this);
autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
@@ -745,10 +775,11 @@ void RPCConsole::clear(bool clearHistory)
message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
- tr("Type <b>help</b> for an overview of available commands.")) +
- "<br><span class=\"secwarning\">" +
+ tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
+ tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
+ "<br><span class=\"secwarning\"><br>" +
tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
- "</span>",
+ "</span>"),
true);
}
@@ -930,18 +961,6 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value)
setTrafficGraphRange(mins);
}
-QString RPCConsole::FormatBytes(quint64 bytes)
-{
- if(bytes < 1024)
- return QString(tr("%1 B")).arg(bytes);
- if(bytes < 1024 * 1024)
- return QString(tr("%1 KB")).arg(bytes / 1024);
- if(bytes < 1024 * 1024 * 1024)
- return QString(tr("%1 MB")).arg(bytes / 1024 / 1024);
-
- return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
-}
-
void RPCConsole::setTrafficGraphRange(int mins)
{
ui->trafficGraph->setGraphRangeMins(mins);
@@ -950,8 +969,8 @@ void RPCConsole::setTrafficGraphRange(int mins)
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
{
- ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
- ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
+ ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
+ ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
}
void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
@@ -1045,8 +1064,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
- ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes));
- ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
+ ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
+ ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index da06818f87..5960410cdd 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_QT_RPCCONSOLE_H
#define BITCOIN_QT_RPCCONSOLE_H
-#include "guiutil.h"
-#include "peertablemodel.h"
+#include <qt/guiutil.h>
+#include <qt/peertablemodel.h>
-#include "net.h"
+#include <net.h>
#include <QWidget>
#include <QCompleter>
@@ -123,7 +123,6 @@ Q_SIGNALS:
void cmdRequest(const QString &command);
private:
- static QString FormatBytes(quint64 bytes);
void startExecutor();
void setTrafficGraphRange(int mins);
/** show detailed information on ui about selected node */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 0f66d117a8..faddfcd4d0 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -2,34 +2,31 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sendcoinsdialog.h"
-#include "ui_sendcoinsdialog.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "coincontroldialog.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "sendcoinsentry.h"
-#include "walletmodel.h"
-
-#include "base58.h"
-#include "chainparams.h"
-#include "wallet/coincontrol.h"
-#include "validation.h" // mempool and minRelayTxFee
-#include "ui_interface.h"
-#include "txmempool.h"
-#include "policy/fees.h"
-#include "wallet/wallet.h"
+#include <qt/sendcoinsdialog.h>
+#include <qt/forms/ui_sendcoinsdialog.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/coincontroldialog.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/sendcoinsentry.h>
+
+#include <base58.h>
+#include <chainparams.h>
+#include <wallet/coincontrol.h>
+#include <validation.h> // mempool and minRelayTxFee
+#include <ui_interface.h>
+#include <txmempool.h>
+#include <policy/fees.h>
+#include <wallet/fees.h>
#include <QFontMetrics>
-#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
-#include <QTimer>
static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
int getConfTargetForIndex(int index) {
@@ -114,10 +111,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
settings.setValue("nFeeRadio", 1); // custom
if (!settings.contains("nFeeRadio"))
settings.setValue("nFeeRadio", 0); // recommended
- if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
- settings.setValue("nCustomFeeRadio", 1); // total at least
- if (!settings.contains("nCustomFeeRadio"))
- settings.setValue("nCustomFeeRadio", 0); // per kilobyte
if (!settings.contains("nSmartFeeSliderPosition"))
settings.setValue("nSmartFeeSliderPosition", 0);
if (!settings.contains("nTransactionFee"))
@@ -127,8 +120,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
ui->groupFee->setId(ui->radioSmartFee, 0);
ui->groupFee->setId(ui->radioCustomFee, 1);
ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
- ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0);
- 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());
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
@@ -178,14 +169,13 @@ void SendCoinsDialog::setModel(WalletModel *_model)
connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
+ ui->customFee->setSingleStep(GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
@@ -214,7 +204,6 @@ SendCoinsDialog::~SendCoinsDialog()
QSettings settings;
settings.setValue("fFeeSectionMinimized", fFeeMinimized);
settings.setValue("nFeeRadio", ui->groupFee->checkedId());
- settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
@@ -353,7 +342,7 @@ void SendCoinsDialog::on_sendButton_clicked()
if (ui->optInRBF->isChecked())
{
questionString.append("<hr /><span>");
- questionString.append(tr("This transaction signals replaceability (optin-RBF)."));
+ questionString.append(tr("You can increase the fee later (signals Replace-By-Fee)."));
questionString.append("</span>");
}
@@ -410,6 +399,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
+ connect(entry, SIGNAL(useAvailableBalance(SendCoinsEntry*)), this, SLOT(useAvailableBalance(SendCoinsEntry*)));
connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels()));
connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels()));
@@ -607,10 +597,34 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
minimizeFeeSection(true);
}
+void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
+{
+ // Get CCoinControl instance if CoinControl is enabled or create a new one.
+ CCoinControl coin_control;
+ if (model->getOptionsModel()->getCoinControlFeatures()) {
+ coin_control = *CoinControlDialog::coinControl;
+ }
+
+ // Calculate available amount to send.
+ CAmount amount = model->getBalance(&coin_control);
+ for (int i = 0; i < ui->entries->count(); ++i) {
+ SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
+ if (e && !e->isHidden() && e != entry) {
+ amount -= e->getValue().amount;
+ }
+ }
+
+ if (amount > 0) {
+ entry->checkSubtractFeeFromAmount();
+ entry->setAmount(amount);
+ } else {
+ entry->setAmount(0);
+ }
+}
+
void SendCoinsDialog::setMinimumFee()
{
- ui->radioCustomPerKilobyte->setChecked(true);
- ui->customFee->setValue(CWallet::GetRequiredFee(1000));
+ ui->customFee->setValue(GetRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
@@ -622,7 +636,7 @@ void SendCoinsDialog::updateFeeSectionControls()
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
- ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
+ ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
}
@@ -634,8 +648,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel()
if (ui->radioSmartFee->isChecked())
ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
else {
- ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) +
- ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : ""));
+ ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB");
}
}
@@ -643,7 +656,7 @@ void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), GetRequiredFee(1000)) + "/kB")
);
}
@@ -668,7 +681,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
updateCoinControlState(coin_control);
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc;
- CFeeRate feeRate = CFeeRate(CWallet::GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
+ CFeeRate feeRate = CFeeRate(GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
@@ -777,22 +790,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
CoinControlDialog::coinControl->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
- CBitcoinAddress addr = CBitcoinAddress(text.toStdString());
+ const CTxDestination dest = DecodeDestination(text.toStdString());
if (text.isEmpty()) // Nothing entered
{
ui->labelCoinControlChangeLabel->setText("");
}
- else if (!addr.IsValid()) // Invalid address
+ else if (!IsValidDestination(dest)) // Invalid address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
else // Valid address
{
- CKeyID keyid;
- addr.GetKeyID(keyid);
- if (!model->havePrivKey(keyid)) // Unknown change address
- {
+ if (!model->IsSpendable(dest)) {
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
// confirmation dialog
@@ -800,7 +810,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Yes)
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
else
{
ui->lineEditCoinControlChange->setText("");
@@ -819,7 +829,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
else
ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
}
}
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 70b4aa5a03..300116fd9f 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_SENDCOINSDIALOG_H
#define BITCOIN_QT_SENDCOINSDIALOG_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QDialog>
#include <QMessageBox>
@@ -76,6 +76,7 @@ private Q_SLOTS:
void on_buttonChooseFee_clicked();
void on_buttonMinimizeFee_clicked();
void removeEntry(SendCoinsEntry* entry);
+ void useAvailableBalance(SendCoinsEntry* entry);
void updateDisplayUnit();
void coinControlFeatureChanged(bool);
void coinControlButtonClicked();
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index bb0f47b21c..4cf4bb9ef7 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -2,15 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sendcoinsentry.h"
-#include "ui_sendcoinsentry.h"
+#include <qt/sendcoinsentry.h>
+#include <qt/forms/ui_sendcoinsentry.h>
-#include "addressbookpage.h"
-#include "addresstablemodel.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "walletmodel.h"
+#include <qt/addressbookpage.h>
+#include <qt/addresstablemodel.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
#include <QApplication>
#include <QClipboard>
@@ -48,6 +47,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par
connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));
+ connect(ui->useAvailableBalanceButton, SIGNAL(clicked()), this, SLOT(useAvailableBalanceClicked()));
}
SendCoinsEntry::~SendCoinsEntry()
@@ -112,11 +112,21 @@ void SendCoinsEntry::clear()
updateDisplayUnit();
}
+void SendCoinsEntry::checkSubtractFeeFromAmount()
+{
+ ui->checkboxSubtractFeeFromAmount->setChecked(true);
+}
+
void SendCoinsEntry::deleteClicked()
{
Q_EMIT removeEntry(this);
}
+void SendCoinsEntry::useAvailableBalanceClicked()
+{
+ Q_EMIT useAvailableBalance(this);
+}
+
bool SendCoinsEntry::validate()
{
if (!model)
@@ -228,6 +238,11 @@ void SendCoinsEntry::setAddress(const QString &address)
ui->payAmount->setFocus();
}
+void SendCoinsEntry::setAmount(const CAmount &amount)
+{
+ ui->payAmount->setValue(amount);
+}
+
bool SendCoinsEntry::isClear()
{
return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index a8be670c2a..b470a0d72e 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_SENDCOINSENTRY_H
#define BITCOIN_QT_SENDCOINSENTRY_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QStackedWidget>
@@ -38,6 +38,7 @@ public:
void setValue(const SendCoinsRecipient &value);
void setAddress(const QString &address);
+ void setAmount(const CAmount &amount);
/** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases
* (issue https://bugreports.qt-project.org/browse/QTBUG-10907).
@@ -48,14 +49,17 @@ public:
public Q_SLOTS:
void clear();
+ void checkSubtractFeeFromAmount();
Q_SIGNALS:
void removeEntry(SendCoinsEntry *entry);
+ void useAvailableBalance(SendCoinsEntry* entry);
void payAmountChanged();
void subtractFeeFromAmountChanged();
private Q_SLOTS:
void deleteClicked();
+ void useAvailableBalanceClicked();
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
void on_pasteButton_clicked();
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 0950ed0234..4cd0c76b16 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "signverifymessagedialog.h"
-#include "ui_signverifymessagedialog.h"
+#include <qt/signverifymessagedialog.h>
+#include <qt/forms/ui_signverifymessagedialog.h>
-#include "addressbookpage.h"
-#include "guiutil.h"
-#include "platformstyle.h"
-#include "walletmodel.h"
+#include <qt/addressbookpage.h>
+#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
+#include <qt/walletmodel.h>
-#include "base58.h"
-#include "init.h"
-#include "validation.h" // For strMessageMagic
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <init.h>
+#include <validation.h> // For strMessageMagic
+#include <wallet/wallet.h>
#include <string>
#include <vector>
@@ -117,16 +117,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
/* Clear old signature to ensure users don't get confused on error with an old signature displayed */
ui->signatureOut_SM->clear();
- CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ const CKeyID* keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -142,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!model->getPrivKey(keyID, key))
+ if (!model->getPrivKey(*keyID, key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
@@ -164,7 +162,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
- ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
+ ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig.data(), vchSig.size())));
}
void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
@@ -197,16 +195,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
- CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ if (!boost::get<CKeyID>(&destination)) {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -237,8 +232,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- if (!(CBitcoinAddress(pubkey.GetID()) == addr))
- {
+ if (!(CTxDestination(pubkey.GetID()) == destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 1b7cc69231..5aa1de5553 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -3,21 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "splashscreen.h"
+#include <qt/splashscreen.h>
-#include "networkstyle.h"
+#include <qt/networkstyle.h>
-#include "clientversion.h"
-#include "init.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "version.h"
+#include <clientversion.h>
+#include <init.h>
+#include <util.h>
+#include <ui_interface.h>
+#include <version.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#endif
#include <QApplication>
@@ -142,8 +142,8 @@ SplashScreen::~SplashScreen()
bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
if (ev->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- if(keyEvent->text()[0] == 'q' && breakAction != nullptr) {
- breakAction();
+ if(keyEvent->text()[0] == 'q') {
+ StartShutdown();
}
}
return QObject::eventFilter(obj, ev);
@@ -170,27 +170,18 @@ static void InitMessage(SplashScreen *splash, const std::string &message)
Q_ARG(QColor, QColor(55,55,55)));
}
-static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress)
+static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible)
{
- InitMessage(splash, title + strprintf("%d", nProgress) + "%");
-}
-
-void SplashScreen::setBreakAction(const std::function<void(void)> &action)
-{
- breakAction = action;
-}
-
-static void SetProgressBreakAction(SplashScreen *splash, const std::function<void(void)> &action)
-{
- QMetaObject::invokeMethod(splash, "setBreakAction",
- Qt::QueuedConnection,
- Q_ARG(std::function<void(void)>, action));
+ InitMessage(splash, title + std::string("\n") +
+ (resume_possible ? _("(press q to shutdown and continue later)")
+ : _("press q to shutdown")) +
+ strprintf("\n%d", nProgress) + "%");
}
#ifdef ENABLE_WALLET
void SplashScreen::ConnectWallet(CWallet* wallet)
{
- wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
+ wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, false));
connectedWallets.push_back(wallet);
}
#endif
@@ -199,8 +190,7 @@ void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
- uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
- uiInterface.SetProgressBreakAction.connect(boost::bind(SetProgressBreakAction, this, _1));
+ uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, _3));
#ifdef ENABLE_WALLET
uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1));
#endif
@@ -210,10 +200,10 @@ void SplashScreen::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
- uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, _3));
#ifdef ENABLE_WALLET
for (CWallet* const & pwallet : connectedWallets) {
- pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, false));
}
#endif
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index a88ebb98a8..c6cfd503f7 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -36,8 +36,6 @@ public Q_SLOTS:
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);
- /** Sets the break action */
- void setBreakAction(const std::function<void(void)> &action);
protected:
bool eventFilter(QObject * obj, QEvent * ev);
@@ -55,8 +53,6 @@ private:
int curAlignment;
QList<CWallet*> connectedWallets;
-
- std::function<void(void)> breakAction;
};
#endif // BITCOIN_QT_SPLASHSCREEN_H
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
index 2a7284b5b2..7a4388e940 100644
--- a/src/qt/test/compattests.cpp
+++ b/src/qt/test/compattests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentrequestplus.h" // this includes protobuf's port.h which defines its own bswap macos
+#include <qt/paymentrequestplus.h> // this includes protobuf's port.h which defines its own bswap macos
-#include "compattests.h"
+#include <qt/test/compattests.h>
-#include "compat/byteswap.h"
+#include <compat/byteswap.h>
void CompatTests::bswapTests()
{
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index d9fb869821..1864604372 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentservertests.h"
+#include <qt/test/paymentservertests.h>
-#include "optionsmodel.h"
-#include "paymentrequestdata.h"
+#include <qt/optionsmodel.h>
+#include <qt/test/paymentrequestdata.h>
-#include "amount.h"
-#include "random.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <amount.h>
+#include <random.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
@@ -24,7 +24,7 @@ X509 *parse_b64der_cert(const char* cert_data)
{
std::vector<unsigned char> data = DecodeBase64(cert_data);
assert(data.size() > 0);
- const unsigned char* dptr = &data[0];
+ const unsigned char* dptr = data.data();
X509 *cert = d2i_X509(nullptr, &dptr, data.size());
assert(cert);
return cert;
@@ -43,7 +43,7 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
// Write data to a temp file:
QTemporaryFile f;
f.open();
- f.write((const char*)&data[0], data.size());
+ f.write((const char*)data.data(), data.size());
f.close();
// Create a QObject, install event filter from PaymentServer
@@ -139,7 +139,7 @@ void PaymentServerTests::paymentServerTests()
// Contains a testnet paytoaddress, so payment request network doesn't match client network:
data = DecodeBase64(paymentrequest1_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized, because network "main" is default, even for
// uninitialized payment requests and that will fail our test here.
@@ -148,7 +148,7 @@ void PaymentServerTests::paymentServerTests()
// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
data = DecodeBase64(paymentrequest2_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -159,7 +159,7 @@ void PaymentServerTests::paymentServerTests()
// 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
// -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
data = DecodeBase64(paymentrequest3_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -170,7 +170,7 @@ void PaymentServerTests::paymentServerTests()
// 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
// 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
data = DecodeBase64(paymentrequest4_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -190,7 +190,7 @@ void PaymentServerTests::paymentServerTests()
// Payment request with amount overflow (amount is set to 21000001 BTC):
data = DecodeBase64(paymentrequest5_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -205,7 +205,7 @@ void PaymentServerTests::paymentServerTests()
delete server;
}
-void RecipientCatcher::getRecipient(SendCoinsRecipient r)
+void RecipientCatcher::getRecipient(const SendCoinsRecipient& r)
{
recipient = r;
}
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index 9ffcbb02ac..6d84c38287 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
#define BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
-#include "../paymentserver.h"
+#include <qt/paymentserver.h>
#include <QObject>
#include <QTest>
@@ -26,7 +26,7 @@ class RecipientCatcher : public QObject
Q_OBJECT
public Q_SLOTS:
- void getRecipient(SendCoinsRecipient r);
+ void getRecipient(const SendCoinsRecipient& r);
public:
SendCoinsRecipient recipient;
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index e2abfb3742..0596ccf90e 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -2,19 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpcnestedtests.h"
-
-#include "chainparams.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "validation.h"
-#include "rpc/register.h"
-#include "rpc/server.h"
-#include "rpcconsole.h"
-#include "test/testutil.h"
-#include "test/test_bitcoin.h"
-#include "univalue.h"
-#include "util.h"
+#include <qt/test/rpcnestedtests.h>
+
+#include <chainparams.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <validation.h>
+#include <rpc/register.h>
+#include <rpc/server.h>
+#include <qt/rpcconsole.h>
+#include <test/test_bitcoin.h>
+#include <univalue.h>
+#include <util.h>
#include <QDir>
#include <QtGlobal>
@@ -29,7 +28,7 @@ static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
static const CRPCCommand vRPCCommands[] =
{
- { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
+ { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} },
};
void RPCNestedTests::rpcNestedTests()
@@ -37,11 +36,6 @@ void RPCNestedTests::rpcNestedTests()
// do some test setup
// could be moved to a more generic place when we add more tests on QT level
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
- ClearDatadirCache();
- std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
- QDir dir(QString::fromStdString(path));
- dir.mkpath(".");
- gArgs.ForceSetArg("-datadir", path);
//mempool.setSanityCheck(1.0);
TestingSetup test;
@@ -69,13 +63,13 @@ void RPCNestedTests::rpcNestedTests()
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
QVERIFY(result.substr(0,1) == "{");
- (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
QVERIFY(result == "null");
(RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
QVERIFY(result == result2);
- (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed
+ (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed
QVERIFY(result == result2);
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
@@ -136,6 +130,4 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif
-
- fs::remove_all(fs::path(path));
}
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
index 9ad409019f..04a9d124aa 100644
--- a/src/qt/test/rpcnestedtests.h
+++ b/src/qt/test/rpcnestedtests.h
@@ -8,8 +8,8 @@
#include <QObject>
#include <QTest>
-#include "txdb.h"
-#include "txmempool.h"
+#include <txdb.h>
+#include <txmempool.h>
class RPCNestedTests : public QObject
{
@@ -17,9 +17,6 @@ class RPCNestedTests : public QObject
private Q_SLOTS:
void rpcNestedTests();
-
-private:
- CCoinsViewDB *pcoinsdbview;
};
#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 1b28a285f1..2e11b4f4d6 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -3,18 +3,18 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparams.h"
-#include "rpcnestedtests.h"
-#include "util.h"
-#include "uritests.h"
-#include "compattests.h"
+#include <chainparams.h>
+#include <qt/test/rpcnestedtests.h>
+#include <util.h>
+#include <qt/test/uritests.h>
+#include <qt/test/compattests.h>
#ifdef ENABLE_WALLET
-#include "paymentservertests.h"
-#include "wallettests.h"
+#include <qt/test/paymentservertests.h>
+#include <qt/test/wallettests.h>
#endif
#include <QApplication>
@@ -53,11 +53,15 @@ int main(int argc, char *argv[])
SetupNetworking();
SelectParams(CBaseChainParams::MAIN);
noui_connect();
+ ClearDatadirCache();
+ fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
+ fs::create_directories(pathTemp);
+ gArgs.ForceSetArg("-datadir", pathTemp.string());
bool fInvalid = false;
// Prefer the "minimal" platform for the test instead of the normal default
- // platform ("xcb", "windows", or "cocoa") so tests can't unintentially
+ // platform ("xcb", "windows", or "cocoa") so tests can't unintentionally
// interfere with any background GUIs and don't require extra resources.
#if defined(WIN32)
_putenv_s("QT_QPA_PLATFORM", "minimal");
@@ -97,5 +101,7 @@ int main(int argc, char *argv[])
}
#endif
+ fs::remove_all(pathTemp);
+
return fInvalid;
}
diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp
index 8b53c0d5c7..e47aa8b546 100644
--- a/src/qt/test/uritests.cpp
+++ b/src/qt/test/uritests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "uritests.h"
+#include <qt/test/uritests.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
#include <QUrl>
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index ff1eb59f16..4b7c3bd726 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,18 +1,22 @@
-#include "wallettests.h"
-
-#include "qt/bitcoinamountfield.h"
-#include "qt/callback.h"
-#include "qt/optionsmodel.h"
-#include "qt/platformstyle.h"
-#include "qt/qvalidatedlineedit.h"
-#include "qt/sendcoinsdialog.h"
-#include "qt/sendcoinsentry.h"
-#include "qt/transactiontablemodel.h"
-#include "qt/transactionview.h"
-#include "qt/walletmodel.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "wallet/wallet.h"
+#include <qt/test/wallettests.h>
+
+#include <qt/bitcoinamountfield.h>
+#include <qt/callback.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/qvalidatedlineedit.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/sendcoinsentry.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionview.h>
+#include <qt/walletmodel.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <wallet/wallet.h>
+#include <qt/overviewpage.h>
+#include <qt/receivecoinsdialog.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/receiverequestdialog.h>
#include <QAbstractButton>
#include <QAction>
@@ -21,6 +25,9 @@
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
+#include <QTextEdit>
+#include <QListView>
+#include <QDialogButtonBox>
namespace
{
@@ -57,11 +64,11 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false)
}
//! Send coins to address and return txid.
-uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
+uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
{
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<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
sendCoinsDialog.findChild<QFrame*>("frameFee")
->findChild<QFrame*>("frameFeeSelection")
@@ -140,7 +147,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
// src/qt/test/test_bitcoin-qt -platform xcb # Linux
// src/qt/test/test_bitcoin-qt -platform windows # Windows
// src/qt/test/test_bitcoin-qt -platform cocoa # macOS
-void TestSendCoins()
+void TestGUI()
{
// Set up wallet and chain with 105 blocks (5 mature blocks for spending).
TestChain100Setup test;
@@ -157,7 +164,10 @@ void TestSendCoins()
wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
}
- wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
+ {
+ LOCK(cs_main);
+ wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true);
+ }
wallet.SetBroadcastTransactions(true);
// Create widgets for sending coins and listing transactions.
@@ -172,8 +182,8 @@ void TestSendCoins()
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
- uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
- uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
+ uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
+ uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
@@ -184,6 +194,68 @@ void TestSendCoins()
BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
+ // Check current balance on OverviewPage
+ OverviewPage overviewPage(platformStyle.get());
+ overviewPage.setWalletModel(&walletModel);
+ QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
+ QString balanceText = balanceLabel->text();
+ int unit = walletModel.getOptionsModel()->getDisplayUnit();
+ CAmount balance = walletModel.getBalance();
+ QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
+ QCOMPARE(balanceText, balanceComparison);
+
+ // Check Request Payment button
+ ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
+ receiveCoinsDialog.setModel(&walletModel);
+ RecentRequestsTableModel* requestTableModel = walletModel.getRecentRequestsTableModel();
+
+ // Label input
+ QLineEdit* labelInput = receiveCoinsDialog.findChild<QLineEdit*>("reqLabel");
+ labelInput->setText("TEST_LABEL_1");
+
+ // Amount input
+ BitcoinAmountField* amountInput = receiveCoinsDialog.findChild<BitcoinAmountField*>("reqAmount");
+ amountInput->setValue(1);
+
+ // Message input
+ QLineEdit* messageInput = receiveCoinsDialog.findChild<QLineEdit*>("reqMessage");
+ messageInput->setText("TEST_MESSAGE_1");
+ int initialRowCount = requestTableModel->rowCount({});
+ QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton");
+ requestPaymentButton->click();
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("ReceiveRequestDialog")) {
+ ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget);
+ QTextEdit* rlist = receiveRequestDialog->QObject::findChild<QTextEdit*>("outUri");
+ QString paymentText = rlist->toPlainText();
+ QStringList paymentTextList = paymentText.split('\n');
+ QCOMPARE(paymentTextList.at(0), QString("Payment information"));
+ QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bitcoin:")) != -1);
+ QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
+ QCOMPARE(paymentTextList.at(3), QString("Amount: 0.00000001 ") + QString::fromStdString(CURRENCY_UNIT));
+ QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
+ QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
+ }
+ }
+
+ // Clear button
+ QPushButton* clearButton = receiveCoinsDialog.findChild<QPushButton*>("clearButton");
+ clearButton->click();
+ QCOMPARE(labelInput->text(), QString(""));
+ QCOMPARE(amountInput->value(), CAmount(0));
+ QCOMPARE(messageInput->text(), QString(""));
+
+ // Check addition to history
+ int currentRowCount = requestTableModel->rowCount({});
+ QCOMPARE(currentRowCount, initialRowCount+1);
+
+ // Check Remove button
+ QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView");
+ table->selectRow(currentRowCount-1);
+ QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton");
+ removeRequestButton->click();
+ QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
+
bitdb.Flush(true);
bitdb.Reset();
}
@@ -192,5 +264,5 @@ void TestSendCoins()
void WalletTests::walletTests()
{
- TestSendCoins();
+ TestGUI();
}
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 5bb863451f..b5e4ccb406 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "trafficgraphwidget.h"
-#include "clientmodel.h"
+#include <qt/trafficgraphwidget.h>
+#include <qt/clientmodel.h>
#include <QPainter>
#include <QColor>
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index bcacc47ef3..3f245e6c33 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -2,21 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiondesc.h"
-
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "paymentserver.h"
-#include "transactionrecord.h"
-
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "validation.h"
-#include "script/script.h"
-#include "timedata.h"
-#include "util.h"
-#include "wallet/db.h"
-#include "wallet/wallet.h"
+#include <qt/transactiondesc.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/paymentserver.h>
+#include <qt/transactionrecord.h>
+
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <validation.h>
+#include <script/script.h>
+#include <timedata.h>
+#include <util.h>
+#include <wallet/db.h>
+#include <wallet/wallet.h>
#include <stdint.h>
#include <string>
@@ -24,7 +24,7 @@
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
AssertLockHeld(cs_main);
- if (!CheckFinalTx(wtx))
+ if (!CheckFinalTx(*wtx.tx))
{
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
@@ -91,9 +91,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (nNet > 0)
{
// Credit
- if (CBitcoinAddress(rec->address).IsValid())
- {
- CTxDestination address = CBitcoinAddress(rec->address).Get();
+ CTxDestination address = DecodeDestination(rec->address);
+ if (IsValidDestination(address)) {
if (wallet->mapAddressBook.count(address))
{
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
@@ -118,7 +117,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Online transaction
std::string strAddress = wtx.mapValue["to"];
strHTML += "<b>" + tr("To") + ":</b> ";
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
@@ -189,7 +188,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("To") + ":</b> ";
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
+ strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
else if(toSelf & ISMINE_WATCH_ONLY)
@@ -304,7 +303,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
{
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
+ strHTML += QString::fromStdString(EncodeDestination(address));
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp
index 65f163deb2..74d7a8f525 100644
--- a/src/qt/transactiondescdialog.cpp
+++ b/src/qt/transactiondescdialog.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiondescdialog.h"
-#include "ui_transactiondescdialog.h"
+#include <qt/transactiondescdialog.h>
+#include <qt/forms/ui_transactiondescdialog.h>
-#include "transactiontablemodel.h"
+#include <qt/transactiontablemodel.h>
#include <QModelIndex>
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 44e4ef8238..47890fc7e2 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -2,15 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionfilterproxy.h"
+#include <qt/transactionfilterproxy.h>
-#include "transactiontablemodel.h"
-#include "transactionrecord.h"
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionrecord.h>
#include <cstdlib>
-#include <QDateTime>
-
// Earliest date that can be represented (far in the past)
const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
// Last date that can be represented (far in the future)
@@ -20,7 +18,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
QSortFilterProxyModel(parent),
dateFrom(MIN_DATE),
dateTo(MAX_DATE),
- addrPrefix(),
+ m_search_string(),
typeFilter(ALL_TYPES),
watchOnlyFilter(WatchOnlyFilter_All),
minAmount(0),
@@ -38,6 +36,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool();
QString address = index.data(TransactionTableModel::AddressRole).toString();
QString label = index.data(TransactionTableModel::LabelRole).toString();
+ QString txid = index.data(TransactionTableModel::TxIDRole).toString();
qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());
int status = index.data(TransactionTableModel::StatusRole).toInt();
@@ -51,8 +50,11 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
return false;
if(datetime < dateFrom || datetime > dateTo)
return false;
- if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive))
+ if (!address.contains(m_search_string, Qt::CaseInsensitive) &&
+ ! label.contains(m_search_string, Qt::CaseInsensitive) &&
+ ! txid.contains(m_search_string, Qt::CaseInsensitive)) {
return false;
+ }
if(amount < minAmount)
return false;
@@ -66,9 +68,10 @@ void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime
invalidateFilter();
}
-void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix)
+void TransactionFilterProxy::setSearchString(const QString &search_string)
{
- this->addrPrefix = _addrPrefix;
+ if (m_search_string == search_string) return;
+ m_search_string = search_string;
invalidateFilter();
}
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index 7db02cd61f..fea7502b26 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONFILTERPROXY_H
#define BITCOIN_QT_TRANSACTIONFILTERPROXY_H
-#include "amount.h"
+#include <amount.h>
#include <QDateTime>
#include <QSortFilterProxyModel>
@@ -35,7 +35,7 @@ public:
};
void setDateRange(const QDateTime &from, const QDateTime &to);
- void setAddressPrefix(const QString &addrPrefix);
+ void setSearchString(const QString &);
/**
@note Type filter takes a bit field created with TYPE() or ALL_TYPES
*/
@@ -57,7 +57,7 @@ protected:
private:
QDateTime dateFrom;
QDateTime dateTo;
- QString addrPrefix;
+ QString m_search_string;
quint32 typeFilter;
WatchOnlyFilter watchOnlyFilter;
CAmount minAmount;
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 2ece0d0f28..e3e8377cb9 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionrecord.h"
+#include <qt/transactionrecord.h>
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "validation.h"
-#include "timedata.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <validation.h>
+#include <timedata.h>
+#include <wallet/wallet.h>
#include <stdint.h>
@@ -55,7 +55,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
@@ -127,7 +127,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
@@ -182,7 +182,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = chainActive.Height();
- if (!CheckFinalTx(wtx))
+ if (!CheckFinalTx(*wtx.tx))
{
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
{
@@ -248,7 +248,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.needsUpdate = false;
}
-bool TransactionRecord::statusUpdateNeeded()
+bool TransactionRecord::statusUpdateNeeded() const
{
AssertLockHeld(cs_main);
return status.cur_num_blocks != chainActive.Height() || status.needsUpdate;
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 59f681224f..ee85acf4ac 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_TRANSACTIONRECORD_H
#define BITCOIN_QT_TRANSACTIONRECORD_H
-#include "amount.h"
-#include "uint256.h"
+#include <amount.h>
+#include <uint256.h>
#include <QList>
#include <QString>
@@ -140,7 +140,7 @@ public:
/** Return whether a status update is needed.
*/
- bool statusUpdateNeeded();
+ bool statusUpdateNeeded() const;
};
#endif // BITCOIN_QT_TRANSACTIONRECORD_H
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 59cef555b1..67580f11ae 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiontablemodel.h"
-
-#include "addresstablemodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "transactiondesc.h"
-#include "transactionrecord.h"
-#include "walletmodel.h"
-
-#include "core_io.h"
-#include "validation.h"
-#include "sync.h"
-#include "uint256.h"
-#include "util.h"
-#include "wallet/wallet.h"
+#include <qt/transactiontablemodel.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/transactiondesc.h>
+#include <qt/transactionrecord.h>
+#include <qt/walletmodel.h>
+
+#include <core_io.h>
+#include <validation.h>
+#include <sync.h>
+#include <uint256.h>
+#include <util.h>
+#include <wallet/wallet.h>
#include <QColor>
#include <QDateTime>
@@ -80,10 +80,10 @@ public:
cachedWallet.clear();
{
LOCK2(cs_main, wallet->cs_wallet);
- for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
+ for (const auto& entry : wallet->mapWallet)
{
- if(TransactionRecord::showTransaction(it->second))
- cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
+ if (TransactionRecord::showTransaction(entry.second))
+ cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, entry.second));
}
}
}
@@ -230,7 +230,7 @@ public:
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
{
- std::string strHex = EncodeHexTx(static_cast<CTransaction>(mi->second));
+ std::string strHex = EncodeHexTx(*mi->second.tx);
return QString::fromStdString(strHex);
}
return QString();
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 80aeb64c41..a769707163 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONTABLEMODEL_H
#define BITCOIN_QT_TRANSACTIONTABLEMODEL_H
-#include "bitcoinunits.h"
+#include <qt/bitcoinunits.h>
#include <QAbstractTableModel>
#include <QStringList>
@@ -79,7 +79,7 @@ public:
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
- bool processingQueuedTransactions() { return fProcessingQueuedTransactions; }
+ bool processingQueuedTransactions() const { return fProcessingQueuedTransactions; }
private:
CWallet* wallet;
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 53c38da9db..b7e39e05ec 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -2,23 +2,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionview.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "csvmodelwriter.h"
-#include "editaddressdialog.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "sendcoinsdialog.h"
-#include "transactiondescdialog.h"
-#include "transactionfilterproxy.h"
-#include "transactionrecord.h"
-#include "transactiontablemodel.h"
-#include "walletmodel.h"
-
-#include "ui_interface.h"
+#include <qt/transactionview.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/csvmodelwriter.h>
+#include <qt/editaddressdialog.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/transactiondescdialog.h>
+#include <qt/transactionfilterproxy.h>
+#include <qt/transactionrecord.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/walletmodel.h>
+
+#include <ui_interface.h>
#include <QComboBox>
#include <QDateTimeEdit>
@@ -33,6 +32,7 @@
#include <QScrollBar>
#include <QSignalMapper>
#include <QTableView>
+#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
@@ -94,11 +94,11 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
hlayout->addWidget(typeWidget);
- addressWidget = new QLineEdit(this);
+ search_widget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
- addressWidget->setPlaceholderText(tr("Enter address or label to search"));
+ search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
#endif
- hlayout->addWidget(addressWidget);
+ hlayout->addWidget(search_widget);
amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
@@ -112,6 +112,17 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
+ // Delay before filtering transactions in ms
+ static const int input_filter_delay = 200;
+
+ QTimer* amount_typing_delay = new QTimer(this);
+ amount_typing_delay->setSingleShot(true);
+ amount_typing_delay->setInterval(input_filter_delay);
+
+ QTimer* prefix_typing_delay = new QTimer(this);
+ prefix_typing_delay->setSingleShot(true);
+ prefix_typing_delay->setInterval(input_filter_delay);
+
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0,0,0,0);
vlayout->setSpacing(0);
@@ -173,8 +184,10 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
- connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
- connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
+ connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start()));
+ connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount()));
+ connect(search_widget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
+ connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedSearch()));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
@@ -312,20 +325,19 @@ void TransactionView::chooseWatchonly(int idx)
(TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt());
}
-void TransactionView::changedPrefix(const QString &prefix)
+void TransactionView::changedSearch()
{
if(!transactionProxyModel)
return;
- transactionProxyModel->setAddressPrefix(prefix);
+ transactionProxyModel->setSearchString(search_widget->text());
}
-void TransactionView::changedAmount(const QString &amount)
+void TransactionView::changedAmount()
{
if(!transactionProxyModel)
return;
CAmount amount_parsed = 0;
- if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
- {
+ if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
transactionProxyModel->setMinAmount(amount_parsed);
}
else
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 52e57cae4c..f72a828b00 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONVIEW_H
#define BITCOIN_QT_TRANSACTIONVIEW_H
-#include "guiutil.h"
+#include <qt/guiutil.h>
#include <QWidget>
#include <QKeyEvent>
@@ -66,7 +66,7 @@ private:
QComboBox *dateWidget;
QComboBox *typeWidget;
QComboBox *watchOnlyWidget;
- QLineEdit *addressWidget;
+ QLineEdit *search_widget;
QLineEdit *amountWidget;
QMenu *contextMenu;
@@ -112,8 +112,8 @@ public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
- void changedPrefix(const QString &prefix);
- void changedAmount(const QString &amount);
+ void changedAmount();
+ void changedSearch();
void exportClicked();
void focusTransaction(const QModelIndex&);
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 5d8c23d13c..6d5a2f3101 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -3,23 +3,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "utilitydialog.h"
+#include <qt/utilitydialog.h>
-#include "ui_helpmessagedialog.h"
+#include <qt/forms/ui_helpmessagedialog.h>
-#include "bitcoingui.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "intro.h"
-#include "paymentrequestplus.h"
-#include "guiutil.h"
+#include <qt/bitcoingui.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/intro.h>
+#include <qt/paymentrequestplus.h>
+#include <qt/guiutil.h>
-#include "clientversion.h"
-#include "init.h"
-#include "util.h"
+#include <clientversion.h>
+#include <init.h>
+#include <util.h>
#include <stdio.h>
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index acaa864148..738eeed136 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -41,7 +41,7 @@ class ShutdownWindow : public QWidget
Q_OBJECT
public:
- ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
+ explicit ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
static QWidget *showShutdownWindow(BitcoinGUI *window);
protected:
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index f3183320f0..573b3f1412 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -2,11 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletframe.h"
+#include <qt/walletframe.h>
-#include "bitcoingui.h"
-#include "walletview.h"
+#include <qt/bitcoingui.h>
+#include <qt/walletview.h>
+#include <cassert>
#include <cstdio>
#include <QHBoxLayout>
@@ -69,6 +70,7 @@ bool WalletFrame::setCurrentWallet(const QString& name)
WalletView *walletView = mapWalletViews.value(name);
walletStack->setCurrentWidget(walletView);
+ assert(walletView);
walletView->updateEncryptionStatus();
return true;
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3ca726d0f9..a38e233608 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -2,32 +2,32 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletmodel.h"
-
-#include "addresstablemodel.h"
-#include "consensus/validation.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "paymentserver.h"
-#include "recentrequeststablemodel.h"
-#include "sendcoinsdialog.h"
-#include "transactiontablemodel.h"
-
-#include "base58.h"
-#include "chain.h"
-#include "keystore.h"
-#include "validation.h"
-#include "net.h" // for g_connman
-#include "policy/fees.h"
-#include "policy/rbf.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h" // for GetBoolArg
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h" // for BackupWallet
+#include <qt/walletmodel.h>
+
+#include <qt/addresstablemodel.h>
+#include <consensus/validation.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/paymentserver.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/transactiontablemodel.h>
+
+#include <base58.h>
+#include <chain.h>
+#include <keystore.h>
+#include <validation.h>
+#include <net.h> // for g_connman
+#include <policy/fees.h>
+#include <policy/rbf.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h> // for GetBoolArg
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h> // for BackupWallet
#include <stdint.h>
@@ -188,8 +188,7 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
bool WalletModel::validateAddress(const QString &address)
{
- CBitcoinAddress addressParsed(address.toStdString());
- return addressParsed.IsValid();
+ return IsValidDestinationString(address.toStdString());
}
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
@@ -247,7 +246,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
setAddress.insert(rcp.address);
++nAddresses;
- CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
+ CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString()));
CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -348,7 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
if (!rcp.paymentRequest.IsInitialized())
{
std::string strAddress = rcp.address.toStdString();
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
std::string strLabel = rcp.label.toStdString();
{
LOCK(wallet->cs_wallet);
@@ -464,7 +463,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)
{
- QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString());
+ QString strAddress = QString::fromStdString(EncodeDestination(address));
QString strLabel = QString::fromStdString(label);
QString strPurpose = QString::fromStdString(purpose);
@@ -561,9 +560,9 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
return wallet->GetPubKey(address, vchPubKeyOut);
}
-bool WalletModel::havePrivKey(const CKeyID &address) const
+bool WalletModel::IsSpendable(const CTxDestination& dest) const
{
- return wallet->HaveKey(address);
+ return IsMine(*wallet, dest) & ISMINE_SPENDABLE;
}
bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
@@ -577,10 +576,11 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
LOCK2(cs_main, wallet->cs_wallet);
for (const COutPoint& outpoint : vOutpoints)
{
- if (!wallet->mapWallet.count(outpoint.hash)) continue;
- int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
+ auto it = wallet->mapWallet.find(outpoint.hash);
+ if (it == wallet->mapWallet.end()) continue;
+ int nDepth = it->second.GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
+ COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
vOutputs.push_back(out);
}
}
@@ -595,7 +595,7 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
for (auto& group : wallet->ListCoins()) {
- auto& resultGroup = mapCoins[QString::fromStdString(CBitcoinAddress(group.first).ToString())];
+ auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
for (auto& coin : group.second) {
resultGroup.emplace_back(std::move(coin));
}
@@ -633,7 +633,7 @@ void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
{
- CTxDestination dest = CBitcoinAddress(sAddress).Get();
+ CTxDestination dest = DecodeDestination(sAddress);
std::stringstream ss;
ss << nId;
@@ -659,45 +659,39 @@ bool WalletModel::abandonTransaction(uint256 hash) const
bool WalletModel::transactionCanBeBumped(uint256 hash) const
{
- LOCK2(cs_main, wallet->cs_wallet);
- const CWalletTx *wtx = wallet->GetWalletTx(hash);
- return wtx && SignalsOptInRBF(*wtx) && !wtx->mapValue.count("replaced_by_txid");
+ return feebumper::TransactionCanBeBumped(wallet, hash);
}
bool WalletModel::bumpFee(uint256 hash)
{
- std::unique_ptr<CFeeBumper> feeBump;
- {
- CCoinControl coin_control;
- coin_control.signalRbf = true;
- LOCK2(cs_main, wallet->cs_wallet);
- feeBump.reset(new CFeeBumper(wallet, hash, coin_control, 0));
- }
- if (feeBump->getResult() != BumpFeeResult::OK)
- {
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
+ std::vector<std::string> errors;
+ CAmount old_fee;
+ CAmount new_fee;
+ CMutableTransaction mtx;
+ if (feebumper::CreateTransaction(wallet, hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx) != feebumper::Result::OK) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
- (feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
+ (errors.size() ? QString::fromStdString(errors[0]) : "") +")");
return false;
}
// allow a user based fee verification
QString questionString = tr("Do you want to increase the fee?");
questionString.append("<br />");
- CAmount oldFee = feeBump->getOldFee();
- CAmount newFee = feeBump->getNewFee();
questionString.append("<table style=\"text-align: left;\">");
questionString.append("<tr><td>");
questionString.append(tr("Current fee:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), oldFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), old_fee));
questionString.append("</td></tr><tr><td>");
questionString.append(tr("Increase:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee - oldFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee - old_fee));
questionString.append("</td></tr><tr><td>");
questionString.append(tr("New fee:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee));
questionString.append("</td></tr></table>");
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
confirmationDialog.exec();
@@ -715,23 +709,15 @@ bool WalletModel::bumpFee(uint256 hash)
}
// sign bumped transaction
- bool res = false;
- {
- LOCK2(cs_main, wallet->cs_wallet);
- res = feeBump->signTransaction(wallet);
- }
- if (!res) {
+ if (!feebumper::SignTransaction(wallet, mtx)) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
return false;
}
// commit the bumped transaction
- {
- LOCK2(cs_main, wallet->cs_wallet);
- res = feeBump->commit(wallet);
- }
- if(!res) {
+ uint256 txid;
+ if (feebumper::CommitTransaction(wallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
- QString::fromStdString(feeBump->getErrors()[0])+")");
+ QString::fromStdString(errors[0])+")");
return false;
}
return true;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 6be36a57e2..028146c187 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_QT_WALLETMODEL_H
#define BITCOIN_QT_WALLETMODEL_H
-#include "paymentrequestplus.h"
-#include "walletmodeltransaction.h"
+#include <qt/paymentrequestplus.h>
+#include <qt/walletmodeltransaction.h>
-#include "support/allocators/secure.h"
+#include <support/allocators/secure.h>
#include <map>
#include <vector>
@@ -190,7 +190,7 @@ public:
UnlockContext requestUnlock();
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- bool havePrivKey(const CKeyID &address) const;
+ bool IsSpendable(const CTxDestination& dest) const;
bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index 8bc9ef725e..2188b39b92 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -2,15 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletmodeltransaction.h"
+#include <qt/walletmodeltransaction.h>
-#include "policy/policy.h"
-#include "wallet/wallet.h"
+#include <policy/policy.h>
+#include <wallet/wallet.h>
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
recipients(_recipients),
walletTransaction(0),
- keyChange(0),
fee(0)
{
walletTransaction = new CWalletTx();
@@ -18,26 +17,25 @@ WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &
WalletModelTransaction::~WalletModelTransaction()
{
- delete keyChange;
delete walletTransaction;
}
-QList<SendCoinsRecipient> WalletModelTransaction::getRecipients()
+QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const
{
return recipients;
}
-CWalletTx *WalletModelTransaction::getTransaction()
+CWalletTx *WalletModelTransaction::getTransaction() const
{
return walletTransaction;
}
unsigned int WalletModelTransaction::getTransactionSize()
{
- return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction));
+ return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction->tx));
}
-CAmount WalletModelTransaction::getTransactionFee()
+CAmount WalletModelTransaction::getTransactionFee() const
{
return fee;
}
@@ -79,7 +77,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
}
}
-CAmount WalletModelTransaction::getTotalTransactionAmount()
+CAmount WalletModelTransaction::getTotalTransactionAmount() const
{
CAmount totalTransactionAmount = 0;
for (const SendCoinsRecipient &rcp : recipients)
@@ -91,10 +89,10 @@ CAmount WalletModelTransaction::getTotalTransactionAmount()
void WalletModelTransaction::newPossibleKeyChange(CWallet *wallet)
{
- keyChange = new CReserveKey(wallet);
+ keyChange.reset(new CReserveKey(wallet));
}
CReserveKey *WalletModelTransaction::getPossibleKeyChange()
{
- return keyChange;
+ return keyChange.get();
}
diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h
index 64922efada..519cf9df99 100644
--- a/src/qt/walletmodeltransaction.h
+++ b/src/qt/walletmodeltransaction.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_WALLETMODELTRANSACTION_H
#define BITCOIN_QT_WALLETMODELTRANSACTION_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QObject>
@@ -22,15 +22,15 @@ public:
explicit WalletModelTransaction(const QList<SendCoinsRecipient> &recipients);
~WalletModelTransaction();
- QList<SendCoinsRecipient> getRecipients();
+ QList<SendCoinsRecipient> getRecipients() const;
- CWalletTx *getTransaction();
+ CWalletTx *getTransaction() const;
unsigned int getTransactionSize();
void setTransactionFee(const CAmount& newFee);
- CAmount getTransactionFee();
+ CAmount getTransactionFee() const;
- CAmount getTotalTransactionAmount();
+ CAmount getTotalTransactionAmount() const;
void newPossibleKeyChange(CWallet *wallet);
CReserveKey *getPossibleKeyChange();
@@ -40,7 +40,7 @@ public:
private:
QList<SendCoinsRecipient> recipients;
CWalletTx *walletTransaction;
- CReserveKey *keyChange;
+ std::unique_ptr<CReserveKey> keyChange;
CAmount fee;
};
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 971f5e0e1a..a589fad9bd 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletview.h"
-
-#include "addressbookpage.h"
-#include "askpassphrasedialog.h"
-#include "bitcoingui.h"
-#include "clientmodel.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "overviewpage.h"
-#include "platformstyle.h"
-#include "receivecoinsdialog.h"
-#include "sendcoinsdialog.h"
-#include "signverifymessagedialog.h"
-#include "transactiontablemodel.h"
-#include "transactionview.h"
-#include "walletmodel.h"
-
-#include "ui_interface.h"
+#include <qt/walletview.h>
+
+#include <qt/addressbookpage.h>
+#include <qt/askpassphrasedialog.h>
+#include <qt/bitcoingui.h>
+#include <qt/clientmodel.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/overviewpage.h>
+#include <qt/platformstyle.h>
+#include <qt/receivecoinsdialog.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/signverifymessagedialog.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionview.h>
+#include <qt/walletmodel.h>
+
+#include <ui_interface.h>
#include <QAction>
#include <QActionGroup>
@@ -122,8 +122,8 @@ void WalletView::setWalletModel(WalletModel *_walletModel)
overviewPage->setWalletModel(_walletModel);
receiveCoinsPage->setModel(_walletModel);
sendCoinsPage->setModel(_walletModel);
- usedReceivingAddressesPage->setModel(_walletModel->getAddressTableModel());
- usedSendingAddressesPage->setModel(_walletModel->getAddressTableModel());
+ usedReceivingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
+ usedSendingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
if (_walletModel)
{
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index c1f8422f0c..4c90874135 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_WALLETVIEW_H
#define BITCOIN_QT_WALLETVIEW_H
-#include "amount.h"
+#include <amount.h>
#include <QStackedWidget>
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index d78d9a2358..aa6c273431 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "winshutdownmonitor.h"
+#include <qt/winshutdownmonitor.h>
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
-#include "init.h"
-#include "util.h"
+#include <init.h>
+#include <util.h>
#include <windows.h>
diff --git a/src/random.cpp b/src/random.cpp
index b004bfa91e..3075a77182 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
+#include <random.h>
-#include "crypto/sha512.h"
-#include "support/cleanse.h"
+#include <crypto/sha512.h>
+#include <support/cleanse.h>
#ifdef WIN32
-#include "compat.h" // for Windows API
+#include <compat.h> // for Windows API
#include <wincrypt.h>
#endif
-#include "util.h" // for LogPrint()
-#include "utilstrencodings.h" // for GetTime()
+#include <util.h> // for LogPrint()
+#include <utilstrencodings.h> // for GetTime()
#include <stdlib.h>
#include <limits>
@@ -46,10 +46,10 @@
#include <openssl/err.h>
#include <openssl/rand.h>
-static void RandFailure()
+[[noreturn]] static void RandFailure()
{
LogPrintf("Failed to read randomness, aborting\n");
- abort();
+ std::abort();
}
static inline int64_t GetPerformanceCounter()
@@ -242,7 +242,7 @@ void GetOSRand(unsigned char *ent32)
}
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
// We need a fallback for OSX < 10.12
- if (&getentropy != NULL) {
+ if (&getentropy != nullptr) {
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
diff --git a/src/random.h b/src/random.h
index c60ab36179..a984545467 100644
--- a/src/random.h
+++ b/src/random.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
-#include "crypto/chacha20.h"
-#include "crypto/common.h"
-#include "uint256.h"
+#include <crypto/chacha20.h>
+#include <crypto/common.h>
+#include <uint256.h>
#include <stdint.h>
@@ -128,7 +128,7 @@ public:
* sure that the underlying OS APIs for all platforms support the number.
* (many cap out at 256 bytes).
*/
-static const ssize_t NUM_OS_RANDOM_BYTES = 32;
+static const int NUM_OS_RANDOM_BYTES = 32;
/** Get 32 bytes of system entropy. Do not use this in application code: use
* GetStrongRandBytes instead.
diff --git a/src/rest.cpp b/src/rest.cpp
index 6a4b005f90..86ee7804a3 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,20 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "core_io.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "validation.h"
-#include "httpserver.h"
-#include "rpc/blockchain.h"
-#include "rpc/server.h"
-#include "streams.h"
-#include "sync.h"
-#include "txmempool.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <core_io.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <validation.h>
+#include <httpserver.h>
+#include <rpc/blockchain.h>
+#include <rpc/server.h>
+#include <streams.h>
+#include <sync.h>
+#include <txmempool.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <boost/algorithm/string.hpp>
@@ -48,7 +48,7 @@ struct CCoin {
ADD_SERIALIZE_METHODS;
CCoin() : nHeight(0) {}
- CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
+ explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
@@ -178,8 +178,11 @@ static bool rest_headers(HTTPRequest* req,
}
case RF_JSON: {
UniValue jsonHeaders(UniValue::VARR);
- for (const CBlockIndex *pindex : headers) {
- jsonHeaders.push_back(blockheaderToJSON(pindex));
+ {
+ LOCK(cs_main);
+ for (const CBlockIndex *pindex : headers) {
+ jsonHeaders.push_back(blockheaderToJSON(pindex));
+ }
}
std::string strJSON = jsonHeaders.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -190,9 +193,6 @@ static bool rest_headers(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block(HTTPRequest* req,
@@ -242,7 +242,11 @@ static bool rest_block(HTTPRequest* req,
}
case RF_JSON: {
- UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ UniValue objBlock;
+ {
+ LOCK(cs_main);
+ objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ }
std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
@@ -253,9 +257,6 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)
@@ -292,9 +293,6 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
@@ -317,9 +315,6 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
@@ -342,9 +337,6 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
@@ -394,9 +386,6 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
@@ -427,10 +416,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (uriParts.size() > 0)
{
-
//inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
- if (uriParts.size() > 0 && uriParts[0] == "checkmempool")
- fCheckMemPool = true;
+ if (uriParts[0] == "checkmempool") fCheckMemPool = true;
for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
{
@@ -581,9 +568,6 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static const struct {
diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h
index 46789e5417..ab467f07c9 100644
--- a/src/reverse_iterator.h
+++ b/src/reverse_iterator.h
@@ -17,7 +17,7 @@ class reverse_range
T &m_x;
public:
- reverse_range(T &x) : m_x(x) {}
+ explicit reverse_range(T &x) : m_x(x) {}
auto begin() const -> decltype(this->m_x.rbegin())
{
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 24e0405a84..b7895b86f7 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -3,27 +3,28 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/blockchain.h"
-
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "coins.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "core_io.h"
-#include "policy/feerate.h"
-#include "policy/policy.h"
-#include "primitives/transaction.h"
-#include "rpc/server.h"
-#include "streams.h"
-#include "sync.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "hash.h"
+#include <rpc/blockchain.h>
+
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <coins.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <core_io.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <primitives/transaction.h>
+#include <rpc/server.h>
+#include <streams.h>
+#include <sync.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <hash.h>
+#include <warnings.h>
#include <stdint.h>
@@ -77,6 +78,7 @@ double GetDifficulty(const CBlockIndex* blockindex)
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
+ AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
@@ -105,6 +107,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)
{
+ AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
@@ -125,7 +128,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
txs.push_back(objTx);
}
else
@@ -343,6 +346,7 @@ std::string EntryDescriptionString()
" \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n"
" \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n"
" \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n"
+ " \"wtxid\" : hash, (string) hash of serialized transaction, including witness data\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n";
@@ -363,6 +367,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("ancestorcount", e.GetCountWithAncestors()));
info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors()));
info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors()));
+ info.push_back(Pair("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString()));
const CTransaction& tx = e.GetTx();
std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin)
@@ -812,6 +817,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ assert(pcursor);
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -922,7 +928,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
CCoinsStats stats;
FlushStateToDisk();
- if (GetUTXOStats(pcoinsdbview, stats)) {
+ if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
@@ -944,9 +950,10 @@ UniValue gettxout(const JSONRPCRequest& request)
"gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. n (numeric, required) vout number\n"
- "3. include_mempool (boolean, optional) Whether to include the mempool\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "2. \"n\" (numeric, required) vout number\n"
+ "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true."
+ " Note that an unspent output that is spent in the mempool won't appear.\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -989,7 +996,7 @@ UniValue gettxout(const JSONRPCRequest& request)
Coin coin;
if (fMempool) {
LOCK(mempool.cs);
- CCoinsViewMemPool view(pcoinsTip, mempool);
+ CCoinsViewMemPool view(pcoinsTip.get(), mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue;
}
@@ -1041,7 +1048,7 @@ UniValue verifychain(const JSONRPCRequest& request)
if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();
- return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
+ return CVerifyDB().VerifyDB(Params(), pcoinsTip.get(), nCheckLevel, nCheckDepth);
}
/** Implementation of IsSuperMajority with better feedback */
@@ -1106,13 +1113,13 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
return rv;
}
-void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
+void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
// Deployments with timeout value of 0 are hidden.
// A timeout value of 0 guarantees a softfork will never be activated.
// This is used when softfork codes are merged without specifying the deployment schedule.
if (consensusParams.vDeployments[id].nTimeout > 0)
- bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id)));
+ bip9_softforks.push_back(Pair(VersionBitsDeploymentInfo[id].name, BIP9SoftForkDesc(consensusParams, id)));
}
UniValue getblockchaininfo(const JSONRPCRequest& request)
@@ -1123,41 +1130,46 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
"Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
"{\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
- " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
+ " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
+ " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
+ " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
+ " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
- " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
- " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
- " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored\n"
- " \"softforks\": [ (array) status of softforks in progress\n"
+ " \"initialblockdownload\": xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode.\n"
+ " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
+ " \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
+ " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
+ " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
+ " \"automatic_pruning\": xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
+ " \"prune_target_size\": xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled)\n"
+ " \"softforks\": [ (array) status of softforks in progress\n"
" {\n"
- " \"id\": \"xxxx\", (string) name of softfork\n"
- " \"version\": xx, (numeric) block version\n"
- " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
- " \"status\": xx, (boolean) true if threshold reached\n"
+ " \"id\": \"xxxx\", (string) name of softfork\n"
+ " \"version\": xx, (numeric) block version\n"
+ " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
+ " \"status\": xx, (boolean) true if threshold reached\n"
" },\n"
" }, ...\n"
" ],\n"
- " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
- " \"xxxx\" : { (string) name of the softfork\n"
- " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
- " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
- " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
- " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
- " \"since\": xx, (numeric) height of the first block to which the status applies\n"
- " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
- " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
- " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
- " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
- " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
- " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
+ " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
+ " \"xxxx\" : { (string) name of the softfork\n"
+ " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
+ " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
+ " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
+ " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"since\": xx, (numeric) height of the first block to which the status applies\n"
+ " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
+ " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
+ " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
+ " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
+ " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
+ " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
" }\n"
" }\n"
" }\n"
+ " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -1174,8 +1186,26 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()));
obj.push_back(Pair("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())));
+ obj.push_back(Pair("initialblockdownload", IsInitialBlockDownload()));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
+ obj.push_back(Pair("size_on_disk", CalculateCurrentUsage()));
obj.push_back(Pair("pruned", fPruneMode));
+ if (fPruneMode) {
+ CBlockIndex* block = chainActive.Tip();
+ assert(block);
+ while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
+ block = block->pprev;
+ }
+
+ obj.push_back(Pair("pruneheight", block->nHeight));
+
+ // if 0, execution bypasses the whole if block.
+ bool automatic_pruning = (gArgs.GetArg("-prune", 0) != 1);
+ obj.push_back(Pair("automatic_pruning", automatic_pruning));
+ if (automatic_pruning) {
+ obj.push_back(Pair("prune_target_size", nPruneTarget));
+ }
+ }
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
@@ -1184,19 +1214,13 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
- BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV);
- BIP9SoftForkDescPushBack(bip9_softforks, "segwit", consensusParams, Consensus::DEPLOYMENT_SEGWIT);
+ for (int pos = Consensus::DEPLOYMENT_CSV; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) {
+ BIP9SoftForkDescPushBack(bip9_softforks, consensusParams, static_cast<Consensus::DeploymentPos>(pos));
+ }
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));
- if (fPruneMode)
- {
- CBlockIndex *block = chainActive.Tip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))
- block = block->pprev;
-
- obj.push_back(Pair("pruneheight", block->nHeight));
- }
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
@@ -1343,7 +1367,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
- " \"mempoolminfee\": xxxxx (numeric) Minimum feerate (" + CURRENCY_UNIT + " per KB) for tx to be accepted\n"
+ " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
@@ -1477,9 +1501,12 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
"2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n"
"\nResult:\n"
"{\n"
- " \"time\": xxxxx, (numeric) The timestamp for the statistics in UNIX format.\n"
- " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
- " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window.\n"
+ " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
+ " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
+ " \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n"
+ " \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n"
+ " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
+ " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getchaintxstats", "")
@@ -1489,11 +1516,7 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
- if (request.params.size() > 0 && !request.params[0].isNull()) {
- blockcount = request.params[0].get_int();
- }
-
- bool havehash = request.params.size() > 1 && !request.params[1].isNull();
+ bool havehash = !request.params[1].isNull();
uint256 hash;
if (havehash) {
hash = uint256S(request.params[1].get_str());
@@ -1514,9 +1537,17 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
pindex = chainActive.Tip();
}
}
+
+ assert(pindex != nullptr);
- if (blockcount < 1 || blockcount >= pindex->nHeight) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height");
+ if (request.params[0].isNull()) {
+ blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
+ } else {
+ blockcount = request.params[0].get_int();
+
+ if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
+ }
}
const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);
@@ -1526,41 +1557,68 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("time", (int64_t)pindex->nTime));
ret.push_back(Pair("txcount", (int64_t)pindex->nChainTx));
- ret.push_back(Pair("txrate", ((double)nTxDiff) / nTimeDiff));
+ ret.push_back(Pair("window_block_count", blockcount));
+ if (blockcount > 0) {
+ ret.push_back(Pair("window_tx_count", nTxDiff));
+ ret.push_back(Pair("window_interval", nTimeDiff));
+ if (nTimeDiff > 0) {
+ ret.push_back(Pair("txrate", ((double)nTxDiff) / nTimeDiff));
+ }
+ }
return ret;
}
+UniValue savemempool(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "savemempool\n"
+ "\nDumps the mempool to disk.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("savemempool", "")
+ + HelpExampleRpc("savemempool", "")
+ );
+ }
+
+ if (!DumpMempool()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
+ }
+
+ return NullUniValue;
+}
+
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
- { "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
- { "blockchain", "getblockcount", &getblockcount, true, {} },
- { "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|verbose"} },
- { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
- { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} },
- { "blockchain", "getchaintips", &getchaintips, true, {} },
- { "blockchain", "getdifficulty", &getdifficulty, true, {} },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} },
- { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
- { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
- { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
- { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} },
- { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} },
-
- { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, {} },
+ { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, {} },
+ { "blockchain", "getblockcount", &getblockcount, {} },
+ { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
+ { "blockchain", "getblockhash", &getblockhash, {"height"} },
+ { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
+ { "blockchain", "getchaintips", &getchaintips, {} },
+ { "blockchain", "getdifficulty", &getdifficulty, {} },
+ { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} },
+ { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
+ { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
+ { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} },
+ { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {} },
+ { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
+ { "blockchain", "savemempool", &savemempool, {} },
+ { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
+
+ { "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
- { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
- { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
- { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
- { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
+ { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
+ { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} },
+ { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} },
+ { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} },
+ { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} },
};
void RegisterBlockchainRPCCommands(CRPCTable &t)
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4179453782..f2fa114313 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -3,15 +3,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/client.h"
-#include "rpc/protocol.h"
-#include "util.h"
+#include <rpc/client.h>
+#include <rpc/protocol.h>
+#include <util.h>
#include <set>
#include <stdint.h>
-#include <univalue.h>
-
class CRPCConvertParam
{
public:
@@ -115,8 +113,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" },
- { "estimatesmartfee", 0, "nblocks" },
- { "estimaterawfee", 0, "nblocks" },
+ { "estimatesmartfee", 0, "conf_target" },
+ { "estimaterawfee", 0, "conf_target" },
{ "estimaterawfee", 1, "threshold" },
{ "prioritisetransaction", 1, "dummy" },
{ "prioritisetransaction", 2, "fee_delta" },
@@ -129,6 +127,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
{ "disconnectnode", 1, "nodeid" },
+ { "addwitnessaddress", 1, "p2sh" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
@@ -140,6 +139,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "echojson", 7, "arg7" },
{ "echojson", 8, "arg8" },
{ "echojson", 9, "arg9" },
+ { "rescanblockchain", 0, "start_height"},
+ { "rescanblockchain", 1, "stop_height"},
};
class CRPCConvertTable
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f498b5c8ea..d003be4954 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -3,34 +3,32 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "consensus/consensus.h"
-#include "consensus/params.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "init.h"
-#include "validation.h"
-#include "miner.h"
-#include "net.h"
-#include "policy/fees.h"
-#include "pow.h"
-#include "rpc/blockchain.h"
-#include "rpc/mining.h"
-#include "rpc/server.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "warnings.h"
+#include <base58.h>
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <consensus/consensus.h>
+#include <consensus/params.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <init.h>
+#include <validation.h>
+#include <miner.h>
+#include <net.h>
+#include <policy/fees.h>
+#include <pow.h>
+#include <rpc/blockchain.h>
+#include <rpc/mining.h>
+#include <rpc/server.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <warnings.h>
#include <memory>
#include <stdint.h>
-#include <univalue.h>
-
unsigned int ParseConfirmTarget(const UniValue& value)
{
int target = value.get_int();
@@ -176,12 +174,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ CTxDestination destination = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
+ }
std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
- coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
+ coinbaseScript->reserveScript = GetScriptForDestination(destination);
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
@@ -195,14 +194,14 @@ UniValue getmininginfo(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
- " \"currentblocksize\": nnn, (numeric) The last block size\n"
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
- " \"errors\": \"...\" (string) Current errors\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
+ " \"errors\": \"...\" (string) DEPRECATED. Same as warnings. Only shown when bitcoind is started with -deprecatedrpc=getmininginfo\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -214,14 +213,17 @@ UniValue getmininginfo(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
- obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
+ if (IsDeprecatedRPCEnabled("getmininginfo")) {
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ } else {
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
+ }
return obj;
}
@@ -336,7 +338,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
" \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
" \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
@@ -346,7 +348,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)\n"
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
@@ -451,7 +453,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
{
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
- boost::system_time checktxtime;
+ std::chrono::steady_clock::time_point checktxtime;
unsigned int nTransactionsUpdatedLastLP;
if (lpval.isStr())
@@ -472,17 +474,17 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
// Release the wallet and main lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
{
- checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
+ checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
- boost::unique_lock<boost::mutex> lock(csBestBlock);
+ WaitableLock lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
{
- if (!cvBlockChange.timed_wait(lock, checktxtime))
+ if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
{
// Timeout: Check transactions for update
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
- checktxtime += boost::posix_time::seconds(10);
+ checktxtime += std::chrono::seconds(10);
}
}
}
@@ -686,7 +688,7 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
+ explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected:
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
@@ -790,6 +792,12 @@ UniValue estimatefee(const JSONRPCRequest& request)
+ HelpExampleCli("estimatefee", "6")
);
+ if (!IsDeprecatedRPCEnabled("estimatefee")) {
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee is deprecated and will be fully removed in v0.17. "
+ "To use estimatefee in v0.16, restart bitcoind with -deprecatedrpc=estimatefee.\n"
+ "Projects should transition to using estimatesmartfee before upgrading to v0.17");
+ }
+
RPCTypeCheck(request.params, {UniValue::VNUM});
int nBlocks = request.params[0].get_int();
@@ -825,7 +833,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
" \"CONSERVATIVE\"\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
@@ -842,7 +850,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
bool conservative = true;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
FeeEstimateMode fee_mode;
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
@@ -884,7 +892,7 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"short\" : { (json object, optional) estimate for short time horizon\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
" \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
@@ -967,20 +975,21 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
- { "mining", "getmininginfo", &getmininginfo, true, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","dummy","fee_delta"} },
- { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
- { "mining", "submitblock", &submitblock, true, {"hexdata","dummy"} },
+ { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
+ { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
+ { "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
+
- { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
+ { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
- { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatesmartfee", &estimatesmartfee, true, {"conf_target", "estimate_mode"} },
+ { "util", "estimatefee", &estimatefee, {"nblocks"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} },
- { "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
+ { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
index 868d7002b5..8d46273159 100644
--- a/src/rpc/mining.h
+++ b/src/rpc/mining.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_RPC_MINING_H
#define BITCOIN_RPC_MINING_H
-#include "script/script.h"
+#include <script/script.h>
#include <univalue.h>
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index efff4a99ae..327af2e237 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -3,26 +3,27 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "clientversion.h"
-#include "core_io.h"
-#include "init.h"
-#include "validation.h"
-#include "httpserver.h"
-#include "net.h"
-#include "netbase.h"
-#include "rpc/blockchain.h"
-#include "rpc/server.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <base58.h>
+#include <chain.h>
+#include <clientversion.h>
+#include <core_io.h>
+#include <crypto/ripemd160.h>
+#include <init.h>
+#include <validation.h>
+#include <httpserver.h>
+#include <net.h>
+#include <netbase.h>
+#include <rpc/blockchain.h>
+#include <rpc/server.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilstrencodings.h>
#ifdef ENABLE_WALLET
-#include "wallet/rpcwallet.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
#endif
-#include "warnings.h"
+#include <warnings.h>
#include <stdint.h>
#ifdef HAVE_MALLOC_INFO
@@ -31,101 +32,13 @@
#include <univalue.h>
-/**
- * @note Do not add or change anything in the information returned by this
- * method. `getinfo` exists for backwards-compatibility only. It combines
- * information from wildly different sources in the program, which is a mess,
- * and is thus planned to be deprecated eventually.
- *
- * Based on the source of the information, new information should be added to:
- * - `getblockchaininfo`,
- * - `getnetworkinfo` or
- * - `getwalletinfo`
- *
- * Or alternatively, create a specific query method for the information.
- **/
-UniValue getinfo(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
- "getinfo\n"
- "\nDEPRECATED. Returns an object containing various state info.\n"
- "\nResult:\n"
- "{\n"
- " \"deprecation-warning\": \"...\" (string) warning that the getinfo command is deprecated and will be removed in 0.16\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"testnet\": true|false, (boolean) if the server is using testnet or not\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 set in " + CURRENCY_UNIT + "/kB\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
- " \"errors\": \"...\" (string) any error messages\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getinfo", "")
- + HelpExampleRpc("getinfo", "")
- );
-
-#ifdef ENABLE_WALLET
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
-
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
-#else
- LOCK(cs_main);
-#endif
-
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("deprecation-warning", "WARNING: getinfo is deprecated and will be fully removed in 0.16."
- " Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16"));
- obj.push_back(Pair("version", CLIENT_VERSION));
- obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.push_back(Pair("walletversion", pwallet->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
- }
-#endif
- obj.push_back(Pair("blocks", (int)chainActive.Height()));
- 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() : std::string())));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize()));
- }
- if (pwallet && pwallet->IsCrypted()) {
- obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
- }
- obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
-#endif
- obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- return obj;
-}
-
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
CWallet * const pwallet;
- DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
+ explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
@@ -133,6 +46,7 @@ public:
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
+ obj.push_back(Pair("iswitness", false));
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
@@ -144,6 +58,7 @@ public:
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.push_back(Pair("isscript", true));
+ obj.push_back(Pair("iswitness", false));
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
@@ -152,14 +67,56 @@ public:
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
- for (const CTxDestination& addr : addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
}
return obj;
}
+
+ UniValue operator()(const WitnessV0KeyHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CPubKey pubkey;
+ obj.push_back(Pair("isscript", false));
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", 0));
+ obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
+ if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
+ obj.push_back(Pair("pubkey", HexStr(pubkey)));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessV0ScriptHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ obj.push_back(Pair("isscript", true));
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", 0));
+ obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
+ CRIPEMD160 hasher;
+ uint160 hash;
+ hasher.Write(id.begin(), 32).Finalize(hash.begin());
+ if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
+ obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessUnknown& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", (int)id.version));
+ obj.push_back(Pair("witness_program", HexStr(id.program, id.program + id.length)));
+ return obj;
+ }
};
#endif
@@ -207,15 +164,14 @@ UniValue validateaddress(const JSONRPCRequest& request)
LOCK(cs_main);
#endif
- CBitcoinAddress address(request.params[0].get_str());
- bool isValid = address.IsValid();
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
- CTxDestination dest = address.Get();
- std::string currentAddress = address.ToString();
+ std::string currentAddress = EncodeDestination(dest);
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
@@ -230,18 +186,25 @@ UniValue validateaddress(const JSONRPCRequest& request)
if (pwallet && pwallet->mapAddressBook.count(dest)) {
ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
}
- CKeyID keyID;
if (pwallet) {
- const auto& meta = pwallet->mapKeyMetadata;
- auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
- if (it == meta.end()) {
- it = meta.find(CScriptID(scriptPubKey));
+ const CKeyMetadata* meta = nullptr;
+ if (const CKeyID* key_id = boost::get<CKeyID>(&dest)) {
+ auto it = pwallet->mapKeyMetadata.find(*key_id);
+ if (it != pwallet->mapKeyMetadata.end()) {
+ meta = &it->second;
+ }
+ }
+ if (!meta) {
+ auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey));
+ if (it != pwallet->m_script_metadata.end()) {
+ meta = &it->second;
+ }
}
- if (it != meta.end()) {
- ret.push_back(Pair("timestamp", it->second.nCreateTime));
- if (!it->second.hdKeypath.empty()) {
- ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
- ret.push_back(Pair("hdmasterkeyid", it->second.hdMasterKeyID.GetHex()));
+ if (meta) {
+ ret.push_back(Pair("timestamp", meta->nCreateTime));
+ if (!meta->hdKeypath.empty()) {
+ ret.push_back(Pair("hdkeypath", meta->hdKeypath));
+ ret.push_back(Pair("hdmasterkeyid", meta->hdMasterKeyID.GetHex()));
}
}
}
@@ -277,16 +240,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
- CBitcoinAddress address(ks);
- if (pwallet && address.IsValid()) {
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
- throw std::runtime_error(
- strprintf("%s does not refer to a key",ks));
+ CTxDestination dest = DecodeDestination(ks);
+ if (pwallet && IsValidDestination(dest)) {
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
+ throw std::runtime_error(strprintf("%s does not refer to a key", ks));
+ }
CPubKey vchPubKey;
- if (!pwallet->GetPubKey(keyID, vchPubKey)) {
- throw std::runtime_error(
- strprintf("no full public key for address %s",ks));
+ if (!pwallet->GetPubKey(*keyID, vchPubKey)) {
+ throw std::runtime_error(strprintf("no full public key for address %s", ks));
}
if (!vchPubKey.IsFullyValid())
throw std::runtime_error(" Invalid public key: "+ks);
@@ -357,10 +319,9 @@ UniValue createmultisig(const JSONRPCRequest& request)
// Construct using pay-to-script-hash:
CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
- CBitcoinAddress address(innerID);
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("address", EncodeDestination(innerID)));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
@@ -395,13 +356,15 @@ UniValue verifymessage(const JSONRPCRequest& request)
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddress);
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
bool fInvalid = false;
std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
@@ -417,7 +380,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
- return (pubkey.GetID() == keyID);
+ return (pubkey.GetID() == *keyID);
}
UniValue signmessagewithprivkey(const JSONRPCRequest& request)
@@ -459,7 +422,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
- return EncodeBase64(&vchSig[0], vchSig.size());
+ return EncodeBase64(vchSig.data(), vchSig.size());
}
UniValue setmocktime(const JSONRPCRequest& request)
@@ -552,7 +515,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getmemoryinfo", "")
);
- std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str();
+ std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
@@ -577,6 +540,9 @@ uint32_t getCategoryMask(UniValue cats) {
if (!GetLogCategory(&flag, &cat)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
}
+ if (flag == BCLog::NONE) {
+ return 0;
+ }
mask |= flag;
}
return mask;
@@ -586,16 +552,32 @@ UniValue logging(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(
- "logging [include,...] <exclude>\n"
+ "logging ( <include> <exclude> )\n"
"Gets and sets the logging configuration.\n"
- "When called without an argument, returns the list of categories that are currently being debug logged.\n"
- "When called with arguments, adds or removes categories from debug logging.\n"
+ "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
+ "When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
+ "The arguments are evaluated in order \"include\", \"exclude\".\n"
+ "If an item is both included and excluded, it will thus end up being excluded.\n"
"The valid logging categories are: " + ListLogCategories() + "\n"
- "libevent logging is configured on startup and cannot be modified by this RPC during runtime."
- "Arguments:\n"
- "1. \"include\" (array of strings) add debug logging for these categories.\n"
- "2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
- "\nResult: <categories> (string): a list of the logging categories that are active.\n"
+ "In addition, the following are available as category names with special meanings:\n"
+ " - \"all\", \"1\" : represent all logging categories.\n"
+ " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
+ "\nArguments:\n"
+ "1. \"include\" (array of strings, optional) A json array of categories to add debug logging\n"
+ " [\n"
+ " \"category\" (string) the valid logging category\n"
+ " ,...\n"
+ " ]\n"
+ "2. \"exclude\" (array of strings, optional) A json array of categories to remove debug logging\n"
+ " [\n"
+ " \"category\" (string) the valid logging category\n"
+ " ,...\n"
+ " ]\n"
+ "\nResult:\n"
+ "{ (json object where keys are the logging categories, and values indicates its status\n"
+ " \"category\": 0|1, (numeric) if being debug logged or not. 0:inactive, 1:active\n"
+ " ...\n"
+ "}\n"
"\nExamples:\n"
+ HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
+ HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
@@ -603,11 +585,11 @@ UniValue logging(const JSONRPCRequest& request)
}
uint32_t originalLogCategories = logCategories;
- if (request.params.size() > 0 && request.params[0].isArray()) {
+ if (request.params[0].isArray()) {
logCategories |= getCategoryMask(request.params[0]);
}
- if (request.params.size() > 1 && request.params[1].isArray()) {
+ if (request.params[1].isArray()) {
logCategories &= ~getCategoryMask(request.params[1]);
}
@@ -649,20 +631,19 @@ UniValue echo(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
- { "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"} },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
+ { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
+ { "control", "logging", &logging, {"include", "exclude"}},
+ { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
- { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "logging", &logging, true, {"include", "exclude"}},
+ { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
+ { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index e463a4eda4..9de249855c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
-
-#include "chainparams.h"
-#include "clientversion.h"
-#include "core_io.h"
-#include "validation.h"
-#include "net.h"
-#include "net_processing.h"
-#include "netbase.h"
-#include "policy/policy.h"
-#include "protocol.h"
-#include "sync.h"
-#include "timedata.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
-#include "warnings.h"
+#include <rpc/server.h>
+
+#include <chainparams.h>
+#include <clientversion.h>
+#include <core_io.h>
+#include <validation.h>
+#include <net.h>
+#include <net_processing.h>
+#include <netbase.h>
+#include <policy/policy.h>
+#include <rpc/protocol.h>
+#include <sync.h>
+#include <timedata.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
+#include <warnings.h>
#include <univalue.h>
@@ -92,7 +92,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
- " \"addnode\": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot\n"
+ " \"addnode\": true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\n"
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
@@ -146,7 +146,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
if (stats.dPingTime > 0.0)
obj.push_back(Pair("pingtime", stats.dPingTime));
- if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)
+ if (stats.dMinPing < static_cast<double>(std::numeric_limits<int64_t>::max())/1e6)
obj.push_back(Pair("minping", stats.dMinPing));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
@@ -156,7 +156,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
// their ver message.
obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
- obj.push_back(Pair("addnode", stats.fAddnode));
+ obj.push_back(Pair("addnode", stats.m_manual_connection));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
@@ -193,7 +193,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() == 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
@@ -201,6 +201,8 @@ UniValue addnode(const JSONRPCRequest& request)
"addnode \"node\" \"add|remove|onetry\"\n"
"\nAttempts to add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
+ "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"
+ "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
"2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n"
@@ -217,7 +219,7 @@ UniValue addnode(const JSONRPCRequest& request)
if (strCommand == "onetry")
{
CAddress addr;
- g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true);
return NullUniValue;
}
@@ -258,7 +260,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)
bool success;
const UniValue &address_arg = request.params[0];
- const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1];
+ const UniValue &id_arg = request.params[1];
if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
@@ -311,7 +313,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (request.params.size() == 1 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
@@ -447,7 +449,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ]\n"
- " \"warnings\": \"...\" (string) any network warnings\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -490,7 +492,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() >= 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
@@ -534,11 +536,11 @@ UniValue setban(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
- if (request.params.size() >= 3 && !request.params[2].isNull())
+ if (!request.params[2].isNull())
banTime = request.params[2].get_int64();
bool absolute = false;
- if (request.params.size() == 4 && request.params[3].isTrue())
+ if (request.params[3].isTrue())
absolute = true;
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
@@ -569,11 +571,11 @@ UniValue listbanned(const JSONRPCRequest& request)
g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
- for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ for (const auto& entry : banMap)
{
- CBanEntry banEntry = (*it).second;
+ const CBanEntry& banEntry = entry.second;
UniValue rec(UniValue::VOBJ);
- rec.push_back(Pair("address", (*it).first.ToString()));
+ rec.push_back(Pair("address", entry.first.ToString()));
rec.push_back(Pair("banned_until", banEntry.nBanUntil));
rec.push_back(Pair("ban_created", banEntry.nCreateTime));
rec.push_back(Pair("ban_reason", banEntry.banReasonToString()));
@@ -623,20 +625,20 @@ UniValue setnetworkactive(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true, {} },
- { "network", "ping", &ping, true, {} },
- { "network", "getpeerinfo", &getpeerinfo, true, {} },
- { "network", "addnode", &addnode, true, {"node","command"} },
- { "network", "disconnectnode", &disconnectnode, true, {"address", "nodeid"} },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} },
- { "network", "getnettotals", &getnettotals, true, {} },
- { "network", "getnetworkinfo", &getnetworkinfo, true, {} },
- { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} },
- { "network", "listbanned", &listbanned, true, {} },
- { "network", "clearbanned", &clearbanned, true, {} },
- { "network", "setnetworkactive", &setnetworkactive, true, {"state"} },
+ { "network", "getconnectioncount", &getconnectioncount, {} },
+ { "network", "ping", &ping, {} },
+ { "network", "getpeerinfo", &getpeerinfo, {} },
+ { "network", "addnode", &addnode, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
+ { "network", "getnettotals", &getnettotals, {} },
+ { "network", "getnetworkinfo", &getnetworkinfo, {} },
+ { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
+ { "network", "listbanned", &listbanned, {} },
+ { "network", "clearbanned", &clearbanned, {} },
+ { "network", "setnetworkactive", &setnetworkactive, {"state"} },
};
void RegisterNetRPCCommands(CRPCTable &t)
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index db0626b5e1..d999a08d74 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -3,23 +3,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/protocol.h"
+#include <rpc/protocol.h>
-#include "random.h"
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "utiltime.h"
-#include "version.h"
+#include <random.h>
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <utiltime.h>
+#include <version.h>
-#include <stdint.h>
#include <fstream>
/**
* 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
* unspecified (HTTP errors and contents of 'error').
- *
+ *
* 1.0 spec: http://json-rpc.org/wiki/specification
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
@@ -66,9 +65,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
-fs::path GetAuthCookieFile()
+/** Get name of RPC authentication cookie file */
+static fs::path GetAuthCookieFile(bool temp=false)
{
- fs::path path(gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ if (temp) {
+ arg += ".tmp";
+ }
+ fs::path path(arg);
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
@@ -84,14 +88,20 @@ bool GenerateAuthCookie(std::string *cookie_out)
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
- fs::path filepath = GetAuthCookieFile();
- file.open(filepath.string().c_str());
+ fs::path filepath_tmp = GetAuthCookieFile(true);
+ file.open(filepath_tmp.string().c_str());
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
}
file << cookie;
file.close();
+
+ fs::path filepath = GetAuthCookieFile(false);
+ if (!RenameOver(filepath_tmp, filepath)) {
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ return false;
+ }
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
@@ -124,3 +134,22 @@ void DeleteAuthCookie()
}
}
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
+{
+ if (!in.isArray()) {
+ throw std::runtime_error("Batch must be an array");
+ }
+ std::vector<UniValue> batch(num);
+ for (size_t i=0; i<in.size(); ++i) {
+ const UniValue &rec = in[i];
+ if (!rec.isObject()) {
+ throw std::runtime_error("Batch member must be object");
+ }
+ size_t id = rec["id"].get_int();
+ if (id >= num) {
+ throw std::runtime_error("Batch member id larger than size");
+ }
+ batch[id] = rec;
+ }
+ return batch;
+}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 4bd4702d62..4b9bd41994 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_RPCPROTOCOL_H
#define BITCOIN_RPCPROTOCOL_H
-#include "fs.h"
+#include <fs.h>
#include <list>
#include <map>
@@ -57,6 +57,7 @@ enum RPCErrorCode
RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
RPC_IN_WARMUP = -28, //!< Client still warming up
+ RPC_METHOD_DEPRECATED = -32, //!< RPC method is deprecated
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -91,13 +92,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
-/** Get name of RPC authentication cookie file */
-fs::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */
bool GetAuthCookie(std::string *cookie_out);
/** Delete RPC authentication cookie from disk */
void DeleteAuthCookie();
+/** Parse JSON-RPC batch reply into a vector */
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 8100511854..fbebdf44d4 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -3,32 +3,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "coins.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "init.h"
-#include "keystore.h"
-#include "validation.h"
-#include "merkleblock.h"
-#include "net.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/transaction.h"
-#include "rpc/server.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "script/standard.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "utilstrencodings.h"
+#include <base58.h>
+#include <chain.h>
+#include <coins.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <init.h>
+#include <keystore.h>
+#include <validation.h>
+#include <validationinterface.h>
+#include <merkleblock.h>
+#include <net.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/transaction.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <script/standard.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <utilstrencodings.h>
#ifdef ENABLE_WALLET
-#include "wallet/rpcwallet.h"
-#include "wallet/wallet.h"
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
#endif
+#include <future>
#include <stdint.h>
#include <univalue.h>
@@ -41,7 +44,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
// Blockchain contextual information (confirmations and blocktime) is not
// available to code in bitcoin-common, so we query them here and push the
// data into the returned UniValue.
- TxToUniv(tx, uint256(), entry);
+ TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags());
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -61,12 +64,15 @@ 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)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
- "getrawtransaction \"txid\" ( verbose )\n"
+ "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n"
"\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
- "enabled, it also works for blockchain transactions.\n"
+ "enabled, it also works for blockchain transactions. If the block which contains the transaction\n"
+ "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n"
+ "provided, only that block will be searched and if the transaction is in the mempool or other\n"
+ "blocks, or if this node does not have the given block available, the transaction will not be found.\n"
"DEPRECATED: for now, it also works for transactions with unspent outputs.\n"
"\nReturn the raw transaction data.\n"
@@ -75,13 +81,15 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
- "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
+ "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
+ "3. \"blockhash\" (string, optional) The block in which to look for the transaction\n"
"\nResult (if verbose is not set or set to false):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
"\nResult (if verbose is set to true):\n"
"{\n"
+ " \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
@@ -129,45 +137,56 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true")
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
);
LOCK(cs_main);
+ bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ CBlockIndex* blockindex = nullptr;
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
if (!request.params[1].isNull()) {
- if (request.params[1].isNum()) {
- if (request.params[1].get_int() != 0) {
- fVerbose = true;
- }
- }
- else if(request.params[1].isBool()) {
- if(request.params[1].isTrue()) {
- fVerbose = true;
- }
- }
- else {
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
+ fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool();
+ }
+
+ if (!request.params[2].isNull()) {
+ uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
+ BlockMap::iterator it = mapBlockIndex.find(blockhash);
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
+ blockindex = it->second;
+ in_active_chain = chainActive.Contains(blockindex);
}
CTransactionRef tx;
- uint256 hashBlock;
- if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction"
- : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
- ". Use gettransaction for wallet transactions.");
-
- std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
+ uint256 hash_block;
+ if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, true, blockindex)) {
+ std::string errmsg;
+ if (blockindex) {
+ if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
+ }
+ errmsg = "No such transaction found in the provided block";
+ } else {
+ errmsg = fTxIndex
+ ? "No such mempool or blockchain transaction"
+ : "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
+ }
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
+ }
- if (!fVerbose)
- return strHex;
+ if (!fVerbose) {
+ return EncodeHexTx(*tx, RPCSerializationFlags());
+ }
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", strHex));
- TxToJSON(*tx, hashBlock, result);
+ if (blockindex) result.push_back(Pair("in_active_chain", in_active_chain));
+ TxToJSON(*tx, hash_block, result);
return result;
}
@@ -330,7 +349,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM}, true);
+ RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM, UniValue::VBOOL}, true);
if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
@@ -339,14 +358,14 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
- bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false;
+ bool rbfOptIn = request.params[3].isTrue();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
@@ -386,7 +405,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
rawTx.vin.push_back(in);
}
- std::set<CBitcoinAddress> setAddress;
+ std::set<CTxDestination> destinations;
std::vector<std::string> addrList = sendTo.getKeys();
for (const std::string& name_ : addrList) {
@@ -396,15 +415,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CTxOut out(0, CScript() << OP_RETURN << data);
rawTx.vout.push_back(out);
} else {
- CBitcoinAddress address(name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
+ CTxDestination destination = DecodeDestination(name_);
+ if (!IsValidDestination(destination)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (!destinations.insert(destination).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(destination);
CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
@@ -483,7 +503,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToUniv(CTransaction(std::move(mtx)), uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
return result;
}
@@ -531,7 +551,7 @@ UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "scripthash") {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
- r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
}
return r;
@@ -572,7 +592,7 @@ UniValue combinerawtransaction(const JSONRPCRequest& request)
" ]\n"
"\nResult:\n"
- "\"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
+ "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
"\nExamples:\n"
+ HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
@@ -706,6 +726,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+ ObserveSafeMode();
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
@@ -735,7 +756,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
fGivenKeys = true;
UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
@@ -757,7 +778,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
// Add previous txouts given in the RPC call:
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
@@ -828,7 +849,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
int nHashType = SIGHASH_ALL;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
static std::map<std::string, int> mapSigHashValues = {
{std::string("ALL"), int(SIGHASH_ALL)},
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
@@ -873,7 +894,12 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
- TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
+ // Unable to sign input and verification failed (possible attempt to partially sign).
+ TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
+ } else {
+ TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ }
}
}
bool fComplete = vErrors.empty();
@@ -911,7 +937,10 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
- LOCK(cs_main);
+ ObserveSafeMode();
+
+ std::promise<void> promise;
+
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
// parse hex string from parameter
@@ -922,9 +951,11 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
const uint256& hashTx = tx->GetHash();
CAmount nMaxRawTxFee = maxTxFee;
- if (request.params.size() > 1 && request.params[1].get_bool())
+ if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;
+ { // cs_main scope
+ LOCK(cs_main);
CCoinsViewCache &view = *pcoinsTip;
bool fHaveChain = false;
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
@@ -936,8 +967,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- bool fLimitFree = true;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, nullptr, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -946,10 +977,28 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
}
+ } else {
+ // If wallet is enabled, ensure that the wallet has been made aware
+ // of the new transaction prior to returning. This prevents a race
+ // where a user might call sendrawtransaction with a transaction
+ // to/from their wallet, immediately call some wallet RPC, and get
+ // a stale result because callbacks have not yet been processed.
+ CallFunctionInValidationInterfaceQueue([&promise] {
+ promise.set_value();
+ });
}
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
+ } else {
+ // Make sure we don't block forever if re-sending
+ // a transaction already in mempool.
+ promise.set_value();
}
+
+ } // cs_main
+
+ promise.get_future().wait();
+
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -958,22 +1007,23 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
{
pnode->PushInventory(inv);
});
+
return hashTx.GetHex();
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
- { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
- { "rawtransactions", "combinerawtransaction", &combinerawtransaction, true, {"txs"} },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
+ { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },
};
void RegisterRawTransactionRPCCommands(CRPCTable &t)
diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp
new file mode 100644
index 0000000000..9f3a9d30b8
--- /dev/null
+++ b/src/rpc/safemode.cpp
@@ -0,0 +1,14 @@
+#include <rpc/safemode.h>
+
+#include <rpc/protocol.h>
+#include <util.h>
+#include <warnings.h>
+
+void ObserveSafeMode()
+{
+ std::string warning = GetWarnings("rpc");
+ if (warning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE)) {
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + warning);
+ }
+}
+
diff --git a/src/rpc/safemode.h b/src/rpc/safemode.h
new file mode 100644
index 0000000000..8466d6b2f9
--- /dev/null
+++ b/src/rpc/safemode.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPC_SAFEMODE_H
+#define BITCOIN_RPC_SAFEMODE_H
+
+static const bool DEFAULT_DISABLE_SAFEMODE = true;
+
+void ObserveSafeMode();
+
+#endif // BITCOIN_RPC_SAFEMODE_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9ad8d228fa..2e7e0ba474 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -3,18 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
+#include <rpc/server.h>
-#include "base58.h"
-#include "fs.h"
-#include "init.h"
-#include "random.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include <univalue.h>
+#include <base58.h>
+#include <fs.h>
+#include <init.h>
+#include <random.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
@@ -51,11 +49,6 @@ void RPCServer::OnStopped(std::function<void ()> slot)
g_rpcSignals.Stopped.connect(slot);
}
-void RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
-}
-
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected,
bool fAllowNull)
@@ -165,8 +158,8 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
std::set<rpcfn_type> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
- 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));
+ for (const auto& entry : mapCommands)
+ vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
@@ -267,12 +260,12 @@ UniValue uptime(const JSONRPCRequest& jsonRequest)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
- { "control", "help", &help, true, {"command"} },
- { "control", "stop", &stop, true, {} },
- { "control", "uptime", &uptime, true, {} },
+ { "control", "help", &help, {"command"} },
+ { "control", "stop", &stop, {} },
+ { "control", "uptime", &uptime, {} },
};
CRPCTable::CRPCTable()
@@ -387,11 +380,17 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
-static UniValue JSONRPCExecOne(const UniValue& req)
+bool IsDeprecatedRPCEnabled(const std::string& method)
+{
+ const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
+
+ return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
+}
+
+static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
- JSONRPCRequest jreq;
try {
jreq.parse(req);
@@ -411,11 +410,11 @@ static UniValue JSONRPCExecOne(const UniValue& req)
return rpc_result;
}
-std::string JSONRPCExecBatch(const UniValue& vReq)
+std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
{
UniValue ret(UniValue::VARR);
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
- ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
+ ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
return ret.write() + "\n";
}
diff --git a/src/rpc/server.h b/src/rpc/server.h
index dd6f763245..cd201bf316 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_RPCSERVER_H
#define BITCOIN_RPCSERVER_H
-#include "amount.h"
-#include "rpc/protocol.h"
-#include "uint256.h"
+#include <amount.h>
+#include <rpc/protocol.h>
+#include <uint256.h>
#include <list>
#include <map>
@@ -25,13 +25,12 @@ namespace RPCServer
{
void OnStarted(std::function<void ()> slot);
void OnStopped(std::function<void ()> slot);
- void OnPreCommand(std::function<void (const CRPCCommand&)> slot);
}
/** Wrapper for UniValue::VType, which includes typeAny:
* Used to denote don't care type. Only used by RPCTypeCheckObj */
struct UniValueType {
- UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ explicit UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
UniValueType() : typeAny(true) {}
bool typeAny;
UniValue::VType type;
@@ -134,7 +133,6 @@ public:
std::string category;
std::string name;
rpcfn_type actor;
- bool okSafeMode;
std::vector<std::string> argNames;
};
@@ -173,6 +171,8 @@ public:
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
};
+bool IsDeprecatedRPCEnabled(const std::string& method);
+
extern CRPCTable tableRPC;
/**
@@ -191,7 +191,7 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri
bool StartRPC();
void InterruptRPC();
void StopRPC();
-std::string JSONRPCExecBatch(const UniValue& vReq);
+std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq);
// Retrieves any serialization flags requested in command line argument
int RPCSerializationFlags();
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 1d3fb1f6ea..260f6fa60e 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "scheduler.h"
+#include <scheduler.h>
-#include "random.h"
-#include "reverselock.h"
+#include <random.h>
+#include <reverselock.h>
#include <assert.h>
#include <boost/bind.hpp>
@@ -174,7 +174,7 @@ void SingleThreadedSchedulerClient::ProcessQueue() {
// to ensure both happen safely even if callback() throws.
struct RAIICallbacksRunning {
SingleThreadedSchedulerClient* instance;
- RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
+ explicit RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
~RAIICallbacksRunning() {
{
LOCK(instance->m_cs_callbacks_pending);
diff --git a/src/scheduler.h b/src/scheduler.h
index 0365d668b2..b99f165343 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -14,7 +14,7 @@
#include <boost/thread.hpp>
#include <map>
-#include "sync.h"
+#include <sync.h>
//
// Simple class for background tasks that should be run
@@ -81,7 +81,7 @@ private:
int nThreadsServicingQueue;
bool stopRequested;
bool stopWhenEmpty;
- bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
+ bool shouldStop() const { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
};
/**
@@ -102,7 +102,7 @@ private:
void ProcessQueue();
public:
- SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
+ explicit SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
void AddToProcessQueue(std::function<void (void)> func);
// Processes all remaining queue members on the calling thread, blocking until queue is empty
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 03128917fd..77edc85b8c 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
-#include "primitives/transaction.h"
-#include "pubkey.h"
-#include "script/interpreter.h"
-#include "version.h"
+#include <primitives/transaction.h>
+#include <pubkey.h>
+#include <script/interpreter.h>
+#include <version.h>
namespace {
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 33bf80e5a7..f09cd59b92 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -9,7 +9,7 @@
#include <stdint.h>
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#if defined(_WIN32)
#if defined(DLL_EXPORT)
#if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT)
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index f9716dfc66..3c3f92fe46 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -3,15 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "interpreter.h"
+#include <script/interpreter.h>
-#include "primitives/transaction.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "pubkey.h"
-#include "script/script.h"
-#include "uint256.h"
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <uint256.h>
typedef std::vector<unsigned char> valtype;
@@ -349,9 +348,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
// not enabled; treat as a NOP2
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
- }
break;
}
@@ -391,9 +387,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
// not enabled; treat as a NOP3
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
- }
break;
}
@@ -1168,29 +1161,36 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
{
- hashPrevouts = GetPrevoutHash(txTo);
- hashSequence = GetSequenceHash(txTo);
- hashOutputs = GetOutputsHash(txTo);
+ // Cache is calculated only for transactions with witness
+ if (txTo.HasWitness()) {
+ hashPrevouts = GetPrevoutHash(txTo);
+ hashSequence = GetSequenceHash(txTo);
+ hashOutputs = GetOutputsHash(txTo);
+ ready = true;
+ }
}
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
+ assert(nIn < txTo.vin.size());
+
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
+ const bool cacheready = cache && cache->ready;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
+ hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
+ hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo);
}
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
+ hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
@@ -1221,10 +1221,6 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
}
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
- if (nIn >= txTo.vin.size()) {
- // nIn out of range
- return one;
- }
// Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
@@ -1366,7 +1362,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1);
uint256 hashScriptPubKey;
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
- if (memcmp(hashScriptPubKey.begin(), &program[0], 32)) {
+ if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
} else if (program.size() == 20) {
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 437826b5dd..83a96739b1 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SCRIPT_INTERPRETER_H
#define BITCOIN_SCRIPT_INTERPRETER_H
-#include "script_error.h"
-#include "primitives/transaction.h"
+#include <script/script_error.h>
+#include <primitives/transaction.h>
#include <vector>
#include <stdint.h>
@@ -27,37 +27,40 @@ enum
SIGHASH_ANYONECANPAY = 0x80,
};
-/** Script verification flags */
+/** Script verification flags.
+ *
+ * All flags are intended to be soft forks: the set of acceptable scripts under
+ * flags (A | B) is a subset of the acceptable scripts under flag (A).
+ */
enum
{
SCRIPT_VERIFY_NONE = 0,
- // Evaluate P2SH subscripts (softfork safe, BIP16).
+ // Evaluate P2SH subscripts (BIP16).
SCRIPT_VERIFY_P2SH = (1U << 0),
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
- // (softfork safe, but not used or intended as a consensus rule).
+ // (not used or intended as a consensus rule).
SCRIPT_VERIFY_STRICTENC = (1U << 1),
- // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
+ // Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
SCRIPT_VERIFY_DERSIG = (1U << 2),
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
- // (softfork safe, BIP62 rule 5).
+ // (BIP62 rule 5).
SCRIPT_VERIFY_LOW_S = (1U << 3),
- // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
+ // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
- // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
+ // Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
// any other push causes the script to fail (BIP62 rule 3).
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
- // (softfork safe)
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
// Discourage use of NOPs reserved for upgrades (NOP1-10)
@@ -68,12 +71,14 @@ enum
// discouraged NOPs fails the script. This verification flag will never be
// a mandatory flag applied to scripts in a block. NOPs that are not
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
+ // NOPs that have associated forks to give them new meaning (CLTV, CSV)
+ // are not subject to this rule.
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
// Require that only a single stack element remains after evaluation. This changes the success criterion from
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
// "Exactly one stack element must remain, and when interpreted as a boolean, it must be true".
- // (softfork safe, BIP62 rule 6)
+ // (BIP62 rule 6)
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
@@ -113,8 +118,9 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs;
+ bool ready = false;
- PrecomputedTransactionData(const CTransaction& tx);
+ explicit PrecomputedTransactionData(const CTransaction& tx);
};
enum SigVersion
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 0a39619734..5849f55651 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -3,13 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "ismine.h"
+#include <script/ismine.h>
-#include "key.h"
-#include "keystore.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "script/sign.h"
+#include <key.h>
+#include <keystore.h>
+#include <script/script.h>
+#include <script/sign.h>
typedef std::vector<unsigned char> valtype;
@@ -46,6 +45,8 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
+ isInvalid = false;
+
std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
@@ -59,6 +60,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
diff --git a/src/script/ismine.h b/src/script/ismine.h
index 1aa5937b34..77ffa82432 100644
--- a/src/script/ismine.h
+++ b/src/script/ismine.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_ISMINE_H
#define BITCOIN_SCRIPT_ISMINE_H
-#include "script/standard.h"
+#include <script/standard.h>
#include <stdint.h>
diff --git a/src/script/script.cpp b/src/script/script.cpp
index a10b619f7d..a7bfb170eb 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script.h"
+#include <script/script.h>
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <tinyformat.h>
+#include <utilstrencodings.h>
const char* GetOpName(opcodetype opcode)
{
diff --git a/src/script/script.h b/src/script/script.h
index 711ffa97f8..263db62edf 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_SCRIPT_SCRIPT_H
#define BITCOIN_SCRIPT_SCRIPT_H
-#include "crypto/common.h"
-#include "prevector.h"
-#include "serialize.h"
+#include <crypto/common.h>
+#include <prevector.h>
+#include <serialize.h>
#include <assert.h>
#include <climits>
@@ -377,6 +377,12 @@ private:
int64_t m_value;
};
+/**
+ * We use a prevector for the script to reduce the considerable memory overhead
+ * of vectors in cases where they normally contain a small number of small elements.
+ * Tests in October 2015 showed use of this reduced dbcache memory usage by 23%
+ * and made an initial sync 13% faster.
+ */
typedef prevector<28, unsigned char> CScriptBase;
/** Serialized script, used inside transaction inputs and outputs */
@@ -414,6 +420,7 @@ public:
CScript& operator+=(const CScript& b)
{
+ reserve(size() + b.size());
insert(end(), b.begin(), b.end());
return *this;
}
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index c9d13c92a8..32aa639ac4 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script_error.h"
+#include <script/script_error.h>
const char* ScriptErrorString(const ScriptError serror)
{
@@ -73,6 +73,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness version reserved for soft-fork upgrades";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
+ case SCRIPT_ERR_CLEANSTACK:
+ return "Extra items left on stack after execution";
case SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH:
return "Witness program has incorrect length";
case SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY:
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 4cc7afa2f5..88d1d67559 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -3,15 +3,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sigcache.h"
+#include <script/sigcache.h>
-#include "memusage.h"
-#include "pubkey.h"
-#include "random.h"
-#include "uint256.h"
-#include "util.h"
+#include <memusage.h>
+#include <pubkey.h>
+#include <random.h>
+#include <uint256.h>
+#include <util.h>
-#include "cuckoocache.h"
+#include <cuckoocache.h>
#include <boost/thread.hpp>
namespace {
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 5832b264b3..1019061fbb 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_SIGCACHE_H
#define BITCOIN_SCRIPT_SIGCACHE_H
-#include "script/interpreter.h"
+#include <script/interpreter.h>
#include <vector>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index dc50467d3f..117a4d8a52 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script/sign.h"
+#include <script/sign.h>
-#include "key.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "primitives/transaction.h"
-#include "script/standard.h"
-#include "uint256.h"
+#include <key.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <primitives/transaction.h>
+#include <script/standard.h>
+#include <uint256.h>
typedef std::vector<unsigned char> valtype;
@@ -79,6 +79,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
@@ -309,6 +310,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
// Don't know anything about this, assume bigger one is correct:
if (sigs1.script.size() >= sigs2.script.size())
return sigs1;
diff --git a/src/script/sign.h b/src/script/sign.h
index bd45862892..400c0c0865 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_SIGN_H
#define BITCOIN_SCRIPT_SIGN_H
-#include "script/interpreter.h"
+#include <script/interpreter.h>
class CKeyID;
class CKeyStore;
@@ -21,7 +21,7 @@ protected:
const CKeyStore* keystore;
public:
- BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
+ explicit BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
const CKeyStore& KeyStore() const { return *keystore; };
virtual ~BaseSignatureCreator() {}
virtual const BaseSignatureChecker& Checker() const =0;
@@ -54,7 +54,7 @@ public:
/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
- DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
+ explicit DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const override;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 9570b8c8d9..b7b33fade6 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script/standard.h"
+#include <script/standard.h>
-#include "pubkey.h"
-#include "script/script.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <pubkey.h>
+#include <script/script.h>
+#include <util.h>
+#include <utilstrencodings.h>
typedef std::vector<unsigned char> valtype;
@@ -30,13 +30,11 @@ const char* GetTxnOutputType(txnouttype t)
case TX_NULL_DATA: return "nulldata";
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
+ case TX_WITNESS_UNKNOWN: return "witness_unknown";
}
return nullptr;
}
-/**
- * Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
- */
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
{
// Templates
@@ -78,6 +76,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
vSolutionsRet.push_back(witnessprogram);
return true;
}
+ if (witnessversion != 0) {
+ typeRet = TX_WITNESS_UNKNOWN;
+ vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
+ vSolutionsRet.push_back(std::move(witnessprogram));
+ return true;
+ }
return false;
}
@@ -201,6 +205,23 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
addressRet = CScriptID(uint160(vSolutions[0]));
return true;
+ } else if (whichType == TX_WITNESS_V0_KEYHASH) {
+ WitnessV0KeyHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_V0_SCRIPTHASH) {
+ WitnessV0ScriptHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_UNKNOWN) {
+ WitnessUnknown unk;
+ unk.version = vSolutions[0][0];
+ std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
+ unk.length = vSolutions[1].size();
+ addressRet = unk;
+ return true;
}
// Multisig txns have more than one address...
return false;
@@ -253,7 +274,7 @@ class CScriptVisitor : public boost::static_visitor<bool>
private:
CScript *script;
public:
- CScriptVisitor(CScript *scriptin) { script = scriptin; }
+ explicit CScriptVisitor(CScript *scriptin) { script = scriptin; }
bool operator()(const CNoDestination &dest) const {
script->clear();
@@ -271,6 +292,27 @@ public:
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
}
+
+ bool operator()(const WitnessV0KeyHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessUnknown& id) const
+ {
+ script->clear();
+ *script << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
+ return true;
+ }
};
} // namespace
@@ -320,3 +362,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
ret << OP_0 << ToByteVector(hash);
return ret;
}
+
+bool IsValidDestination(const CTxDestination& dest) {
+ return dest.which() != 0;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
index 097e0c3748..3eeeabdc15 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SCRIPT_STANDARD_H
#define BITCOIN_SCRIPT_STANDARD_H
-#include "script/interpreter.h"
-#include "uint256.h"
+#include <script/interpreter.h>
+#include <uint256.h>
#include <boost/variant.hpp>
@@ -27,8 +27,19 @@ public:
CScriptID(const uint160& in) : uint160(in) {}
};
-static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
+/**
+ * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
+ * +2 for the pushdata opcodes.
+ */
+static const unsigned int MAX_OP_RETURN_RELAY = 83;
+
+/**
+ * A data carrying output is an unspendable output containing data. The script
+ * type is designated as TX_NULL_DATA.
+ */
extern bool fAcceptDatacarrier;
+
+/** Maximum size of TX_NULL_DATA scripts that this node considers standard. */
extern unsigned nMaxDatacarrierBytes;
/**
@@ -36,7 +47,7 @@ extern unsigned nMaxDatacarrierBytes;
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
* but in the future other flags may be added, such as a soft-fork to enforce
* strict DER encoding.
- *
+ *
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
* details.
*/
@@ -50,9 +61,10 @@ enum txnouttype
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
- TX_NULL_DATA,
+ TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
TX_WITNESS_V0_SCRIPTHASH,
TX_WITNESS_V0_KEYHASH,
+ TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};
class CNoDestination {
@@ -61,24 +73,98 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
-/**
+struct WitnessV0ScriptHash : public uint256 {};
+struct WitnessV0KeyHash : public uint160 {};
+
+//! CTxDestination subtype to encode any future Witness version
+struct WitnessUnknown
+{
+ unsigned int version;
+ unsigned int length;
+ unsigned char program[40];
+
+ friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version != w2.version) return false;
+ if (w1.length != w2.length) return false;
+ return std::equal(w1.program, w1.program + w1.length, w2.program);
+ }
+
+ friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version < w2.version) return true;
+ if (w1.version > w2.version) return false;
+ if (w1.length < w2.length) return true;
+ if (w1.length > w2.length) return false;
+ return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
+ }
+};
+
+/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
- * * CKeyID: TX_PUBKEYHASH destination
- * * CScriptID: TX_SCRIPTHASH destination
- * A CTxDestination is the internal data type encoded in a CBitcoinAddress
+ * * CKeyID: TX_PUBKEYHASH destination (P2PKH)
+ * * CScriptID: TX_SCRIPTHASH destination (P2SH)
+ * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
+ * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
+ * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
+ * A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
+typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
+/** Check whether a CTxDestination is a CNoDestination. */
+bool IsValidDestination(const CTxDestination& dest);
+
+/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
const char* GetTxnOutputType(txnouttype t);
+/**
+ * Parse a scriptPubKey and identify script type for standard scripts. If
+ * successful, returns script type and parsed pubkeys or hashes, depending on
+ * the type. For example, for a P2SH script, vSolutionsRet will contain the
+ * script hash, for P2PKH it will contain the key hash, etc.
+ *
+ * @param[in] scriptPubKey Script to parse
+ * @param[out] typeRet The script type
+ * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
+ * @return True if script matches standard template
+ */
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+
+/**
+ * Parse a standard scriptPubKey for the destination address. Assigns result to
+ * the addressRet parameter and returns true if successful. For multisig
+ * scripts, instead use ExtractDestinations. Currently only works for P2PK,
+ * P2PKH, P2SH, P2WPKH, and P2WSH scripts.
+ */
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
+
+/**
+ * Parse a standard scriptPubKey with one or more destination addresses. For
+ * multisig scripts, this populates the addressRet vector with the pubkey IDs
+ * and nRequiredRet with the n required to spend. For other destinations,
+ * addressRet is populated with a single value and nRequiredRet is set to 1.
+ * Returns true if successful. Currently does not extract address from
+ * pay-to-witness scripts.
+ */
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
+/**
+ * Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
+ * script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
+ * script for CNoDestination.
+ */
CScript GetScriptForDestination(const CTxDestination& dest);
+
+/** Generate a P2PK script for the given pubkey. */
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
+
+/** Generate a multisig script. */
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
+
+/**
+ * Generate a pay-to-witness script for the given redeem script. If the redeem
+ * script is P2PK or P2PKH, this returns a P2WPKH script, otherwise it returns a
+ * P2WSH script.
+ */
CScript GetScriptForWitness(const CScript& redeemscript);
#endif // BITCOIN_SCRIPT_STANDARD_H
diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h
index 6d27871a7c..7eaf63bf6a 100644
--- a/src/secp256k1/contrib/lax_der_parsing.h
+++ b/src/secp256k1/contrib/lax_der_parsing.h
@@ -48,14 +48,14 @@
* 8.3.1.
*/
-#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
-#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
+#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
+#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
#include <secp256k1.h>
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Parse a signature in "lax DER" format
*
@@ -88,4 +88,4 @@ int ecdsa_signature_parse_der_lax(
}
#endif
-#endif
+#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
index 2fd088f8ab..fece261fb9 100644
--- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
@@ -25,14 +25,14 @@
* library are sufficient.
*/
-#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
-#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
+#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
#include <secp256k1.h>
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Export a private key in DER format.
*
@@ -87,4 +87,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
}
#endif
-#endif
+#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index fc4c5cefbb..3e9c098d19 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -1,9 +1,9 @@
-#ifndef _SECP256K1_
-# define _SECP256K1_
+#ifndef SECP256K1_H
+#define SECP256K1_H
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
#include <stddef.h>
@@ -61,7 +61,7 @@ typedef struct {
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
- * secp256k1_ecdsa_signature_serialize_* functions.
+ * secp256k1_ecdsa_signature_parse_* functions.
*/
typedef struct {
unsigned char data[64];
@@ -159,6 +159,13 @@ typedef int (*secp256k1_nonce_function)(
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
+/** Prefix byte used to tag various encoded curvepoints for specific purposes */
+#define SECP256K1_TAG_PUBKEY_EVEN 0x02
+#define SECP256K1_TAG_PUBKEY_ODD 0x03
+#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
+#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
+#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
+
/** Create a secp256k1 context object.
*
* Returns: a newly created context object.
@@ -607,8 +614,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_H */
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index 4b84d7a963..88492dc1a4 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -1,11 +1,11 @@
-#ifndef _SECP256K1_ECDH_
-# define _SECP256K1_ECDH_
+#ifndef SECP256K1_ECDH_H
+#define SECP256K1_ECDH_H
-# include "secp256k1.h"
+#include "secp256k1.h"
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Compute an EC Diffie-Hellman secret in constant time
* Returns: 1: exponentiation was successful
@@ -24,8 +24,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const unsigned char *privkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_ECDH_H */
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index 0553797253..cf6c5ed7f5 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -1,11 +1,11 @@
-#ifndef _SECP256K1_RECOVERY_
-# define _SECP256K1_RECOVERY_
+#ifndef SECP256K1_RECOVERY_H
+#define SECP256K1_RECOVERY_H
-# include "secp256k1.h"
+#include "secp256k1.h"
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Opaque data structured that holds a parsed ECDSA signature,
* supporting pubkey recovery.
@@ -103,8 +103,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_RECOVERY_H */
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
index 5198724bea..8521f07999 100644
--- a/src/secp256k1/sage/group_prover.sage
+++ b/src/secp256k1/sage/group_prover.sage
@@ -17,7 +17,7 @@
# - A constraint describing the requirements of the law, called "require"
# * Implementations are transliterated into functions that operate as well on
# algebraic input points, and are called once per combination of branches
-# exectured. Each execution returns:
+# executed. Each execution returns:
# - A constraint describing the assumptions this implementation requires
# (such as Z1=1), called "assumeFormula"
# - A constraint describing the assumptions this specific branch requires,
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
index bd2b629e1c..5a9cc3ffcf 100644
--- a/src/secp256k1/src/asm/field_10x26_arm.s
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -23,7 +23,7 @@ Note:
.eabi_attribute 10, 0 @ Tag_FP_arch = none
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
- .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
+ .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
.text
diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h
index c4c16eb7ca..fc588061ca 100644
--- a/src/secp256k1/src/basic-config.h
+++ b/src/secp256k1/src/basic-config.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_BASIC_CONFIG_
-#define _SECP256K1_BASIC_CONFIG_
+#ifndef SECP256K1_BASIC_CONFIG_H
+#define SECP256K1_BASIC_CONFIG_H
#ifdef USE_BASIC_CONFIG
@@ -28,5 +28,6 @@
#define USE_FIELD_10X26 1
#define USE_SCALAR_8X32 1
-#endif // USE_BASIC_CONFIG
-#endif // _SECP256K1_BASIC_CONFIG_
+#endif /* USE_BASIC_CONFIG */
+
+#endif /* SECP256K1_BASIC_CONFIG_H */
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index d67f08a426..d5ebe01301 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_BENCH_H_
-#define _SECP256K1_BENCH_H_
+#ifndef SECP256K1_BENCH_H
+#define SECP256K1_BENCH_H
#include <stdio.h>
#include <math.h>
@@ -63,4 +63,4 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
printf("us\n");
}
-#endif
+#endif /* SECP256K1_BENCH_H */
diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h
index 54ae101b92..80590c7cc8 100644
--- a/src/secp256k1/src/ecdsa.h
+++ b/src/secp256k1/src/ecdsa.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECDSA_
-#define _SECP256K1_ECDSA_
+#ifndef SECP256K1_ECDSA_H
+#define SECP256K1_ECDSA_H
#include <stddef.h>
@@ -18,4 +18,4 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
-#endif
+#endif /* SECP256K1_ECDSA_H */
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 453bb11880..c3400042d8 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -5,8 +5,8 @@
**********************************************************************/
-#ifndef _SECP256K1_ECDSA_IMPL_H_
-#define _SECP256K1_ECDSA_IMPL_H_
+#ifndef SECP256K1_ECDSA_IMPL_H
+#define SECP256K1_ECDSA_IMPL_H
#include "scalar.h"
#include "field.h"
@@ -81,8 +81,6 @@ static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned cha
return -1;
}
while (lenleft > 0) {
- if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
- }
ret = (ret << 8) | **sigp;
if (ret + lenleft > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
@@ -312,4 +310,4 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
return 1;
}
-#endif
+#endif /* SECP256K1_ECDSA_IMPL_H */
diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h
index 42739a3bea..b621f1e6c3 100644
--- a/src/secp256k1/src/eckey.h
+++ b/src/secp256k1/src/eckey.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECKEY_
-#define _SECP256K1_ECKEY_
+#ifndef SECP256K1_ECKEY_H
+#define SECP256K1_ECKEY_H
#include <stddef.h>
@@ -22,4 +22,4 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
-#endif
+#endif /* SECP256K1_ECKEY_H */
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index ce38071ac2..1ab9a68ec0 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECKEY_IMPL_H_
-#define _SECP256K1_ECKEY_IMPL_H_
+#ifndef SECP256K1_ECKEY_IMPL_H
+#define SECP256K1_ECKEY_IMPL_H
#include "eckey.h"
@@ -15,16 +15,17 @@
#include "ecmult_gen.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
- if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
+ if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
secp256k1_fe x;
- return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
+ return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
- if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
+ if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) &&
+ secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
return 0;
}
return secp256k1_ge_is_valid_var(elem);
@@ -42,10 +43,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
secp256k1_fe_get_b32(&pub[1], &elem->x);
if (compressed) {
*size = 33;
- pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
+ pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
} else {
*size = 65;
- pub[0] = 0x04;
+ pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
secp256k1_fe_get_b32(&pub[33], &elem->y);
}
return 1;
@@ -96,4 +97,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx,
return 1;
}
-#endif
+#endif /* SECP256K1_ECKEY_IMPL_H */
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index 20484134f5..6d44aba60b 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_
-#define _SECP256K1_ECMULT_
+#ifndef SECP256K1_ECMULT_H
+#define SECP256K1_ECMULT_H
#include "num.h"
#include "group.h"
@@ -28,4 +28,4 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
-#endif
+#endif /* SECP256K1_ECMULT_H */
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
index 2b0097655c..72bf7d7582 100644
--- a/src/secp256k1/src/ecmult_const.h
+++ b/src/secp256k1/src/ecmult_const.h
@@ -4,12 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_CONST_
-#define _SECP256K1_ECMULT_CONST_
+#ifndef SECP256K1_ECMULT_CONST_H
+#define SECP256K1_ECMULT_CONST_H
#include "scalar.h"
#include "group.h"
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
-#endif
+#endif /* SECP256K1_ECMULT_CONST_H */
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 0db314c48e..7d7a172b7b 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_CONST_IMPL_
-#define _SECP256K1_ECMULT_CONST_IMPL_
+#ifndef SECP256K1_ECMULT_CONST_IMPL_H
+#define SECP256K1_ECMULT_CONST_IMPL_H
#include "scalar.h"
#include "group.h"
@@ -42,11 +42,12 @@
} while(0)
-/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
- * with the following guarantees:
+/** Convert a number to WNAF notation.
+ * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
+ * It has the following guarantees:
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
* - each wnaf[i] is nonzero
- * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w
+ * - the number of words set is always WNAF_SIZE(w) + 1
*
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
@@ -236,4 +237,4 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
}
}
-#endif
+#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h
index eb2cc9ead6..7564b7015f 100644
--- a/src/secp256k1/src/ecmult_gen.h
+++ b/src/secp256k1/src/ecmult_gen.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_GEN_
-#define _SECP256K1_ECMULT_GEN_
+#ifndef SECP256K1_ECMULT_GEN_H
+#define SECP256K1_ECMULT_GEN_H
#include "scalar.h"
#include "group.h"
@@ -40,4 +40,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp25
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
-#endif
+#endif /* SECP256K1_ECMULT_GEN_H */
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 35f2546077..9615b932dd 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
-#define _SECP256K1_ECMULT_GEN_IMPL_H_
+#ifndef SECP256K1_ECMULT_GEN_IMPL_H
+#define SECP256K1_ECMULT_GEN_IMPL_H
#include "scalar.h"
#include "group.h"
@@ -207,4 +207,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_gej_clear(&gb);
}
-#endif
+#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 4e40104ad4..93d3794cb4 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_IMPL_H_
-#define _SECP256K1_ECMULT_IMPL_H_
+#ifndef SECP256K1_ECMULT_IMPL_H
+#define SECP256K1_ECMULT_IMPL_H
#include <string.h>
@@ -403,4 +403,4 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
}
}
-#endif
+#endif /* SECP256K1_ECMULT_IMPL_H */
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index bbb1ee866c..bb6692ad57 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_
-#define _SECP256K1_FIELD_
+#ifndef SECP256K1_FIELD_H
+#define SECP256K1_FIELD_H
/** Field element module.
*
@@ -129,4 +129,4 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
-#endif
+#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 61ee1e0965..727c5267fb 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_
-#define _SECP256K1_FIELD_REPR_
+#ifndef SECP256K1_FIELD_REPR_H
+#define SECP256K1_FIELD_REPR_H
#include <stdint.h>
@@ -44,4 +44,5 @@ typedef struct {
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
-#endif
+
+#endif /* SECP256K1_FIELD_REPR_H */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 234c13a644..94f8132fc8 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
-#define _SECP256K1_FIELD_REPR_IMPL_H_
+#ifndef SECP256K1_FIELD_REPR_IMPL_H
+#define SECP256K1_FIELD_REPR_IMPL_H
#include "util.h"
#include "num.h"
@@ -1158,4 +1158,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index 8e69a560dc..bccd8feb4d 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_
-#define _SECP256K1_FIELD_REPR_
+#ifndef SECP256K1_FIELD_REPR_H
+#define SECP256K1_FIELD_REPR_H
#include <stdint.h>
@@ -44,4 +44,4 @@ typedef struct {
(d6) | (((uint64_t)(d7)) << 32) \
}}
-#endif
+#endif /* SECP256K1_FIELD_REPR_H */
diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h
index 98cc004bf0..1fc3171f6b 100644
--- a/src/secp256k1/src/field_5x52_asm_impl.h
+++ b/src/secp256k1/src/field_5x52_asm_impl.h
@@ -11,8 +11,8 @@
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
*/
-#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
-#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
+#define SECP256K1_FIELD_INNER5X52_IMPL_H
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
@@ -499,4 +499,4 @@ __asm__ __volatile__(
);
}
-#endif
+#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 8e8b286baf..957c61b014 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
-#define _SECP256K1_FIELD_REPR_IMPL_H_
+#ifndef SECP256K1_FIELD_REPR_IMPL_H
+#define SECP256K1_FIELD_REPR_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -493,4 +493,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 0bf22bdd3e..95a0d1791c 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
-#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
+#define SECP256K1_FIELD_INNER5X52_IMPL_H
#include <stdint.h>
@@ -274,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
-#endif
+#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 5127b279bc..20428648af 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_IMPL_H_
-#define _SECP256K1_FIELD_IMPL_H_
+#ifndef SECP256K1_FIELD_IMPL_H
+#define SECP256K1_FIELD_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -312,4 +312,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 4957b248fe..ea1302deb8 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_GROUP_
-#define _SECP256K1_GROUP_
+#ifndef SECP256K1_GROUP_H
+#define SECP256K1_GROUP_H
#include "num.h"
#include "field.h"
@@ -141,4 +141,4 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
-#endif
+#endif /* SECP256K1_GROUP_H */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 7d723532ff..b31b6c12ef 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_GROUP_IMPL_H_
-#define _SECP256K1_GROUP_IMPL_H_
+#ifndef SECP256K1_GROUP_IMPL_H
+#define SECP256K1_GROUP_IMPL_H
#include "num.h"
#include "field.h"
@@ -697,4 +697,4 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
return secp256k1_fe_is_quad_var(&yz);
}
-#endif
+#endif /* SECP256K1_GROUP_IMPL_H */
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index fca98cab9f..e08d25d225 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_HASH_
-#define _SECP256K1_HASH_
+#ifndef SECP256K1_HASH_H
+#define SECP256K1_HASH_H
#include <stdlib.h>
#include <stdint.h>
@@ -38,4 +38,4 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
-#endif
+#endif /* SECP256K1_HASH_H */
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index b47e65f830..4c9964ee06 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_HASH_IMPL_H_
-#define _SECP256K1_HASH_IMPL_H_
+#ifndef SECP256K1_HASH_IMPL_H
+#define SECP256K1_HASH_IMPL_H
#include "hash.h"
@@ -278,4 +278,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
#undef Maj
#undef Ch
-#endif
+#endif /* SECP256K1_HASH_IMPL_H */
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index 9e30fb73dd..01ecba4d53 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_ECDH_MAIN_
-#define _SECP256K1_MODULE_ECDH_MAIN_
+#ifndef SECP256K1_MODULE_ECDH_MAIN_H
+#define SECP256K1_MODULE_ECDH_MAIN_H
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
@@ -51,4 +51,4 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
return ret;
}
-#endif
+#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index 85a5d0a9a6..cec30b67c6 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_ECDH_TESTS_
-#define _SECP256K1_MODULE_ECDH_TESTS_
+#ifndef SECP256K1_MODULE_ECDH_TESTS_H
+#define SECP256K1_MODULE_ECDH_TESTS_H
void test_ecdh_api(void) {
/* Setup context that just counts errors */
@@ -102,4 +102,4 @@ void run_ecdh_tests(void) {
test_bad_scalar();
}
-#endif
+#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index c6fbe23981..2f6691c5a1 100755
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
-#define _SECP256K1_MODULE_RECOVERY_MAIN_
+#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
+#define SECP256K1_MODULE_RECOVERY_MAIN_H
#include "include/secp256k1_recovery.h"
@@ -190,4 +190,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
}
}
-#endif
+#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
index 765c7dd81e..5c9bbe8610 100644
--- a/src/secp256k1/src/modules/recovery/tests_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
-#define _SECP256K1_MODULE_RECOVERY_TESTS_
+#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
+#define SECP256K1_MODULE_RECOVERY_TESTS_H
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void) msg32;
@@ -390,4 +390,4 @@ void run_recovery_tests(void) {
test_ecdsa_recovery_edge_cases();
}
-#endif
+#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index 7bb9c5be8c..49f2dd791d 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_
-#define _SECP256K1_NUM_
+#ifndef SECP256K1_NUM_H
+#define SECP256K1_NUM_H
#ifndef USE_NUM_NONE
@@ -71,4 +71,4 @@ static void secp256k1_num_negate(secp256k1_num *r);
#endif
-#endif
+#endif /* SECP256K1_NUM_H */
diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h
index 7dd813088a..3619844bd5 100644
--- a/src/secp256k1/src/num_gmp.h
+++ b/src/secp256k1/src/num_gmp.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_REPR_
-#define _SECP256K1_NUM_REPR_
+#ifndef SECP256K1_NUM_REPR_H
+#define SECP256K1_NUM_REPR_H
#include <gmp.h>
@@ -17,4 +17,4 @@ typedef struct {
int limbs;
} secp256k1_num;
-#endif
+#endif /* SECP256K1_NUM_REPR_H */
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 3a46495eea..0ae2a8ba0e 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_REPR_IMPL_H_
-#define _SECP256K1_NUM_REPR_IMPL_H_
+#ifndef SECP256K1_NUM_REPR_IMPL_H
+#define SECP256K1_NUM_REPR_IMPL_H
#include <string.h>
#include <stdlib.h>
@@ -285,4 +285,4 @@ static void secp256k1_num_negate(secp256k1_num *r) {
r->neg ^= 1;
}
-#endif
+#endif /* SECP256K1_NUM_REPR_IMPL_H */
diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h
index 0b0e3a072a..c45193b033 100644
--- a/src/secp256k1/src/num_impl.h
+++ b/src/secp256k1/src/num_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_IMPL_H_
-#define _SECP256K1_NUM_IMPL_H_
+#ifndef SECP256K1_NUM_IMPL_H
+#define SECP256K1_NUM_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -21,4 +21,4 @@
#error "Please select num implementation"
#endif
-#endif
+#endif /* SECP256K1_NUM_IMPL_H */
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 27e9d8375e..59304cb66e 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_
-#define _SECP256K1_SCALAR_
+#ifndef SECP256K1_SCALAR_H
+#define SECP256K1_SCALAR_H
#include "num.h"
@@ -103,4 +103,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
-#endif
+#endif /* SECP256K1_SCALAR_H */
diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h
index cff406038f..19c7495d1c 100644
--- a/src/secp256k1/src/scalar_4x64.h
+++ b/src/secp256k1/src/scalar_4x64.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
@@ -16,4 +16,4 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 56e7bd82af..db1ebf94be 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
@@ -946,4 +946,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h
index 1319664f65..2c9a348e24 100644
--- a/src/secp256k1/src/scalar_8x32.h
+++ b/src/secp256k1/src/scalar_8x32.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
@@ -16,4 +16,4 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index aae4f35c08..4f9ed61fea 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)
@@ -718,4 +718,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 2690d86558..fa790570ff 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_IMPL_H_
-#define _SECP256K1_SCALAR_IMPL_H_
+#ifndef SECP256K1_SCALAR_IMPL_H
+#define SECP256K1_SCALAR_IMPL_H
#include "group.h"
#include "scalar.h"
@@ -330,4 +330,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
#endif
#endif
-#endif
+#endif /* SECP256K1_SCALAR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_low.h b/src/secp256k1/src/scalar_low.h
index 5574c44c7a..5836febc5b 100644
--- a/src/secp256k1/src/scalar_low.h
+++ b/src/secp256k1/src/scalar_low.h
@@ -4,12 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef uint32_t secp256k1_scalar;
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index 4f94441f49..c80e70c5a2 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
#include "scalar.h"
@@ -111,4 +111,4 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
return *a == *b;
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index f8efa93c7c..f1f9be077e 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_TESTRAND_H_
-#define _SECP256K1_TESTRAND_H_
+#ifndef SECP256K1_TESTRAND_H
+#define SECP256K1_TESTRAND_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -35,4 +35,4 @@ static void secp256k1_rand256_test(unsigned char *b32);
/** Generate pseudorandom bytes with long sequences of zero and one bits. */
static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
-#endif
+#endif /* SECP256K1_TESTRAND_H */
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 15c7b9f12d..1255574209 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_TESTRAND_IMPL_H_
-#define _SECP256K1_TESTRAND_IMPL_H_
+#ifndef SECP256K1_TESTRAND_IMPL_H
+#define SECP256K1_TESTRAND_IMPL_H
#include <stdint.h>
#include <string.h>
@@ -107,4 +107,4 @@ static void secp256k1_rand256_test(unsigned char *b32) {
secp256k1_rand_bytes_test(b32, 32);
}
-#endif
+#endif /* SECP256K1_TESTRAND_IMPL_H */
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 4092a86c91..b0441d8e30 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_UTIL_H_
-#define _SECP256K1_UTIL_H_
+#ifndef SECP256K1_UTIL_H
+#define SECP256K1_UTIL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -110,4 +110,4 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
#endif
-#endif
+#endif /* SECP256K1_UTIL_H */
diff --git a/src/serialize.h b/src/serialize.h
index 8b86a07a76..02d3e4f7c6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
-#include "compat/endian.h"
+#include <compat/endian.h>
#include <algorithm>
#include <assert.h>
@@ -21,7 +21,7 @@
#include <utility>
#include <vector>
-#include "prevector.h"
+#include <prevector.h>
static const unsigned int MAX_SIZE = 0x02000000;
@@ -402,7 +402,7 @@ class CVarInt
protected:
I &n;
public:
- CVarInt(I& nIn) : n(nIn) { }
+ explicit CVarInt(I& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -420,7 +420,7 @@ class CCompactSize
protected:
uint64_t &n;
public:
- CCompactSize(uint64_t& nIn) : n(nIn) { }
+ explicit CCompactSize(uint64_t& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -439,7 +439,7 @@ class LimitedString
protected:
std::string& string;
public:
- LimitedString(std::string& _string) : string(_string) {}
+ explicit LimitedString(std::string& _string) : string(_string) {}
template<typename Stream>
void Unserialize(Stream& s)
@@ -732,8 +732,8 @@ template<typename Stream, typename K, typename T, typename Pred, typename A>
void Serialize(Stream& os, const std::map<K, T, Pred, A>& m)
{
WriteCompactSize(os, m.size());
- for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
- Serialize(os, (*mi));
+ for (const auto& entry : m)
+ Serialize(os, entry);
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
diff --git a/src/streams.h b/src/streams.h
index ed52c5d52d..c26b1f618c 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_STREAMS_H
#define BITCOIN_STREAMS_H
-#include "support/allocators/zeroafterfree.h"
-#include "serialize.h"
+#include <support/allocators/zeroafterfree.h>
+#include <serialize.h>
#include <algorithm>
#include <assert.h>
@@ -82,7 +82,7 @@ class CVectorWriter
* @param[in] nVersionIn Serialization Version (including any flags)
* @param[in] vchDataIn Referenced byte vector to overwrite/append
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
- * grow as necessary to max(index, vec.size()). So to append, use vec.size().
+ * grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
*/
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
{
@@ -91,7 +91,7 @@ class CVectorWriter
}
/*
* (other params same as above)
- * @param[in] args A list of items to serialize starting at nPos.
+ * @param[in] args A list of items to serialize starting at nPosIn.
*/
template <typename... Args>
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
@@ -332,7 +332,7 @@ public:
//
bool eof() const { return size() == 0; }
CDataStream* rdbuf() { return this; }
- int in_avail() { return size(); }
+ int in_avail() const { return size(); }
void SetType(int n) { nType = n; }
int GetType() const { return nType; }
@@ -345,18 +345,16 @@ public:
// Read from the beginning of the buffer
unsigned int nReadPosNext = nReadPos + nSize;
- if (nReadPosNext >= vch.size())
+ if (nReadPosNext > vch.size()) {
+ throw std::ios_base::failure("CDataStream::read(): end of data");
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ if (nReadPosNext == vch.size())
{
- if (nReadPosNext > vch.size())
- {
- throw std::ios_base::failure("CDataStream::read(): end of data");
- }
- memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
return;
}
- memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
}
@@ -455,10 +453,6 @@ public:
class CAutoFile
{
private:
- // Disallow copies
- CAutoFile(const CAutoFile&);
- CAutoFile& operator=(const CAutoFile&);
-
const int nType;
const int nVersion;
@@ -475,6 +469,10 @@ public:
fclose();
}
+ // Disallow copies
+ CAutoFile(const CAutoFile&) = delete;
+ CAutoFile& operator=(const CAutoFile&) = delete;
+
void fclose()
{
if (file) {
@@ -564,10 +562,6 @@ public:
class CBufferedFile
{
private:
- // Disallow copies
- CBufferedFile(const CBufferedFile&);
- CBufferedFile& operator=(const CBufferedFile&);
-
const int nType;
const int nVersion;
@@ -609,6 +603,10 @@ public:
fclose();
}
+ // Disallow copies
+ CBufferedFile(const CBufferedFile&) = delete;
+ CBufferedFile& operator=(const CBufferedFile&) = delete;
+
int GetVersion() const { return nVersion; }
int GetType() const { return nType; }
@@ -648,7 +646,7 @@ public:
}
// return the current reading position
- uint64_t GetPos() {
+ uint64_t GetPos() const {
return nReadPos;
}
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index f20f424941..7cd031bfe8 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
#define BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
-#include "support/lockedpool.h"
-#include "support/cleanse.h"
+#include <support/lockedpool.h>
+#include <support/cleanse.h>
#include <string>
@@ -26,13 +26,13 @@ struct secure_allocator : public std::allocator<T> {
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
- secure_allocator() throw() {}
- secure_allocator(const secure_allocator& a) throw() : base(a) {}
+ secure_allocator() noexcept {}
+ secure_allocator(const secure_allocator& a) noexcept : base(a) {}
template <typename U>
- secure_allocator(const secure_allocator<U>& a) throw() : base(a)
+ secure_allocator(const secure_allocator<U>& a) noexcept : base(a)
{
}
- ~secure_allocator() throw() {}
+ ~secure_allocator() noexcept {}
template <typename _Other>
struct rebind {
typedef secure_allocator<_Other> other;
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 581d5d6318..23ef96c13f 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
#define BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
-#include "support/cleanse.h"
+#include <support/cleanse.h>
#include <memory>
#include <vector>
@@ -22,13 +22,13 @@ struct zero_after_free_allocator : public std::allocator<T> {
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
- zero_after_free_allocator() throw() {}
- zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
+ zero_after_free_allocator() noexcept {}
+ zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
template <typename U>
- zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a)
+ zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
{
}
- ~zero_after_free_allocator() throw() {}
+ ~zero_after_free_allocator() noexcept {}
template <typename _Other>
struct rebind {
typedef zero_after_free_allocator<_Other> other;
diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp
index a2141b2449..8d3c7369b4 100644
--- a/src/support/cleanse.cpp
+++ b/src/support/cleanse.cpp
@@ -3,11 +3,41 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "cleanse.h"
+#include <support/cleanse.h>
-#include <openssl/crypto.h>
+#include <cstring>
+#if defined(_MSC_VER)
+#include <Windows.h> // For SecureZeroMemory.
+#endif
+
+/* Compilers have a bad habit of removing "superfluous" memset calls that
+ * are trying to zero memory. For example, when memset()ing a buffer and
+ * then free()ing it, the compiler might decide that the memset is
+ * unobservable and thus can be removed.
+ *
+ * Previously we used OpenSSL which tried to stop this by a) implementing
+ * memset in assembly on x86 and b) putting the function in its own file
+ * for other platforms.
+ *
+ * This change removes those tricks in favour of using asm directives to
+ * scare the compiler away. As best as our compiler folks can tell, this is
+ * sufficient and will continue to be so.
+ *
+ * Adam Langley <agl@google.com>
+ * Commit: ad1907fe73334d6c696c8539646c21b11178f20f
+ * BoringSSL (LICENSE: ISC)
+ */
void memory_cleanse(void *ptr, size_t len)
{
- OPENSSL_cleanse(ptr, len);
+ std::memset(ptr, 0, len);
+
+ /* As best as we can tell, this is sufficient to break any optimisations that
+ might try to eliminate "superfluous" memsets. If there's an easy way to
+ detect memset_s, it would be better to use that. */
+#if defined(_MSC_VER)
+ SecureZeroMemory(ptr, len);
+#else
+ __asm__ __volatile__("" : : "r"(ptr) : "memory");
+#endif
}
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 2ead72185f..98e8694181 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "support/lockedpool.h"
-#include "support/cleanse.h"
+#include <support/lockedpool.h>
+#include <support/cleanse.h>
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#ifdef WIN32
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index f5212bc266..834f0371e2 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -50,6 +50,9 @@ public:
Arena(void *base, size_t size, size_t alignment);
virtual ~Arena();
+ Arena(const Arena& other) = delete; // non construction-copyable
+ Arena& operator=(const Arena&) = delete; // non copyable
+
/** Memory statistics. */
struct Stats
{
@@ -85,9 +88,6 @@ public:
*/
bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }
private:
- Arena(const Arena& other) = delete; // non construction-copyable
- Arena& operator=(const Arena&) = delete; // non copyable
-
/** Map of chunk address to chunk information. This class makes use of the
* sorted order to merge previous and next chunks during deallocation.
*/
@@ -150,9 +150,12 @@ public:
* If this callback is provided and returns false, the allocation fails (hard fail), if
* it returns true the allocation proceeds, but it could warn.
*/
- LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = 0);
+ explicit LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);
~LockedPool();
+ LockedPool(const LockedPool& other) = delete; // non construction-copyable
+ LockedPool& operator=(const LockedPool&) = delete; // non copyable
+
/** Allocate size bytes from this arena.
* Returns pointer on success, or 0 if memory is full or
* the application tried to allocate 0 bytes.
@@ -168,9 +171,6 @@ public:
/** Get pool usage statistics */
Stats stats() const;
private:
- LockedPool(const LockedPool& other) = delete; // non construction-copyable
- LockedPool& operator=(const LockedPool&) = delete; // non copyable
-
std::unique_ptr<LockedPageAllocator> allocator;
/** Create an arena from locked pages */
@@ -217,7 +217,7 @@ public:
}
private:
- LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
+ explicit LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
/** Create a new LockedPoolManager specialized to the OS */
static void CreateInstance();
diff --git a/src/sync.cpp b/src/sync.cpp
index b82f3770e4..3f51383ea2 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -2,16 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sync.h"
+#include <sync.h>
-#include "util.h"
-#include "utilstrencodings.h"
+#include <set>
+#include <util.h>
+#include <utilstrencodings.h>
#include <stdio.h>
-#include <boost/thread.hpp>
-
#ifdef DEBUG_LOCKCONTENTION
+#if !defined(HAVE_THREAD_LOCAL)
+static_assert(false, "thread_local is not supported");
+#endif
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
LogPrintf("LOCKCONTENTION: %s\n", pszName);
@@ -45,8 +47,8 @@ struct CLockLocation {
return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
- bool fTry;
private:
+ bool fTry;
std::string mutexName;
std::string sourceFile;
int sourceLine;
@@ -67,10 +69,10 @@ struct LockData {
LockOrders lockorders;
InvLockOrders invlockorders;
- boost::mutex dd_mutex;
+ std::mutex dd_mutex;
} static lockdata;
-boost::thread_specific_ptr<LockStack> lockstack;
+static thread_local std::unique_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
@@ -98,14 +100,14 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
assert(false);
}
-static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
+static void push_lock(void* c, const CLockLocation& locklocation)
{
- if (lockstack.get() == nullptr)
+ if (!lockstack)
lockstack.reset(new LockStack);
- boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
+ std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
- (*lockstack).push_back(std::make_pair(c, locklocation));
+ lockstack->push_back(std::make_pair(c, locklocation));
for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
if (i.first == c)
@@ -130,7 +132,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry));
}
void LeaveCritical()
@@ -155,14 +157,24 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
abort();
}
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
+{
+ for (const std::pair<void*, CLockLocation>& i : *lockstack) {
+ if (i.first == cs) {
+ fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ abort();
+ }
+ }
+}
+
void DeleteLock(void* cs)
{
if (!lockdata.available) {
// We're already shutting down.
return;
}
- boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
- std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
+ std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
+ std::pair<void*, void*> item = std::make_pair(cs, nullptr);
LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
while (it != lockdata.lockorders.end() && it->first.first == cs) {
std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
diff --git a/src/sync.h b/src/sync.h
index 4921aedf39..3af27c65d0 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_SYNC_H
#define BITCOIN_SYNC_H
-#include "threadsafety.h"
+#include <threadsafety.h>
-#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/recursive_mutex.hpp>
+#include <condition_variable>
+#include <thread>
+#include <mutex>
////////////////////////////////////////////////
@@ -21,17 +21,17 @@
/*
CCriticalSection mutex;
- boost::recursive_mutex mutex;
+ std::recursive_mutex mutex;
LOCK(mutex);
- boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
+ std::unique_lock<std::recursive_mutex> criticalblock(mutex);
LOCK2(mutex1, mutex2);
- boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
- boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
+ std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
+ std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
TRY_LOCK(mutex, name);
- boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t);
+ std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
ENTER_CRITICAL_SECTION(mutex); // no RAII
mutex.lock();
@@ -75,20 +75,23 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs
void LeaveCritical();
std::string LocksHeld();
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void DeleteLock(void* cs);
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {}
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
+void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
void static inline DeleteLock(void* cs) {}
#endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
+#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
/**
- * Wrapped boost mutex: supports recursive locking, but no waiting
+ * Wrapped mutex: supports recursive locking, but no waiting
* TODO: We should move away from using the recursive lock by default.
*/
-class CCriticalSection : public AnnotatedMixin<boost::recursive_mutex>
+class CCriticalSection : public AnnotatedMixin<std::recursive_mutex>
{
public:
~CCriticalSection() {
@@ -96,22 +99,24 @@ public:
}
};
-/** Wrapped boost mutex: supports waiting but not recursive locking */
-typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
+/** Wrapped mutex: supports waiting but not recursive locking */
+typedef AnnotatedMixin<std::mutex> CWaitableCriticalSection;
-/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
-typedef boost::condition_variable CConditionVariable;
+/** Just a typedef for std::condition_variable, can be wrapped later if desired */
+typedef std::condition_variable CConditionVariable;
+
+/** Just a typedef for std::unique_lock, can be wrapped later if desired */
+typedef std::unique_lock<std::mutex> WaitableLock;
#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
#endif
-/** Wrapper around boost::unique_lock<Mutex> */
-template <typename Mutex>
-class SCOPED_LOCKABLE CMutexLock
+/** Wrapper around std::unique_lock<CCriticalSection> */
+class SCOPED_LOCKABLE CCriticalBlock
{
private:
- boost::unique_lock<Mutex> lock;
+ std::unique_lock<CCriticalSection> lock;
void Enter(const char* pszName, const char* pszFile, int nLine)
{
@@ -136,7 +141,7 @@ private:
}
public:
- CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
+ CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -144,18 +149,18 @@ public:
Enter(pszName, pszFile, nLine);
}
- CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
+ CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
- lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
+ lock = std::unique_lock<CCriticalSection>(*pmutexIn, std::defer_lock);
if (fTry)
TryEnter(pszName, pszFile, nLine);
else
Enter(pszName, pszFile, nLine);
}
- ~CMutexLock() UNLOCK_FUNCTION()
+ ~CCriticalBlock() UNLOCK_FUNCTION()
{
if (lock.owns_lock())
LeaveCritical();
@@ -167,8 +172,6 @@ public:
}
};
-typedef CMutexLock<CCriticalSection> CCriticalBlock;
-
#define PASTE(x, y) x ## y
#define PASTE2(x, y) PASTE(x, y)
@@ -191,25 +194,23 @@ typedef CMutexLock<CCriticalSection> CCriticalBlock;
class CSemaphore
{
private:
- boost::condition_variable condition;
- boost::mutex mutex;
+ std::condition_variable condition;
+ std::mutex mutex;
int value;
public:
- CSemaphore(int init) : value(init) {}
+ explicit CSemaphore(int init) : value(init) {}
void wait()
{
- boost::unique_lock<boost::mutex> lock(mutex);
- while (value < 1) {
- condition.wait(lock);
- }
+ std::unique_lock<std::mutex> lock(mutex);
+ condition.wait(lock, [&]() { return value >= 1; });
value--;
}
bool try_wait()
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if (value < 1)
return false;
value--;
@@ -219,7 +220,7 @@ public:
void post()
{
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
value++;
}
condition.notify_one();
@@ -267,7 +268,7 @@ public:
CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
- CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
+ explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
{
if (fTry)
TryAcquire();
@@ -280,7 +281,7 @@ public:
Release();
}
- operator bool()
+ operator bool() const
{
return fHaveGrant;
}
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index ffbeeb7d91..6be176a1ad 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -4,17 +4,17 @@
// Unit tests for denial-of-service detection/prevention code
-#include "chainparams.h"
-#include "keystore.h"
-#include "net.h"
-#include "net_processing.h"
-#include "pow.h"
-#include "script/sign.h"
-#include "serialize.h"
-#include "util.h"
-#include "validation.h"
-
-#include "test/test_bitcoin.h"
+#include <chainparams.h>
+#include <keystore.h>
+#include <net.h>
+#include <net_processing.h>
+#include <pow.h>
+#include <script/sign.h>
+#include <serialize.h>
+#include <util.h>
+#include <validation.h>
+
+#include <test/test_bitcoin.h>
#include <stdint.h>
@@ -40,8 +40,141 @@ CService ip(uint32_t i)
static NodeId id = 0;
+void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds);
+
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
+// Test eviction of an outbound peer whose chain never advances
+// Mock a node connection, and use mocktime to simulate a peer
+// which never sends any headers messages. PeerLogic should
+// decide to evict that outbound peer, after the appropriate timeouts.
+// Note that we protect 4 outbound nodes from being subject to
+// this logic; this test takes advantage of that protection only
+// being applied to nodes which send headers with sufficient
+// work.
+BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
+{
+ std::atomic<bool> interruptDummy(false);
+
+ // Mock an outbound peer
+ CAddress addr1(ip(0xa0b0c001), NODE_NONE);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+
+ peerLogic->InitializeNode(&dummyNode1);
+ dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
+
+ // This test requires that we have a chain with non-zero work.
+ LOCK(cs_main);
+ BOOST_CHECK(chainActive.Tip() != nullptr);
+ BOOST_CHECK(chainActive.Tip()->nChainWork > 0);
+
+ // Test starts here
+ LOCK(dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ LOCK(dummyNode1.cs_vSend);
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ dummyNode1.vSendMsg.clear();
+
+ int64_t nStartTime = GetTime();
+ // Wait 21 minutes
+ SetMockTime(nStartTime+21*60);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ // Wait 3 more minutes
+ SetMockTime(nStartTime+24*60);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect
+ BOOST_CHECK(dummyNode1.fDisconnect == true);
+ SetMockTime(0);
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
+}
+
+void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic)
+{
+ CAddress addr(ip(GetRandInt(0xffffffff)), NODE_NONE);
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false));
+ CNode &node = *vNodes.back();
+ node.SetSendVersion(PROTOCOL_VERSION);
+
+ peerLogic.InitializeNode(&node);
+ node.nVersion = 1;
+ node.fSuccessfullyConnected = true;
+
+ CConnmanTest::AddNode(node);
+}
+
+BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ constexpr int nMaxOutbound = 8;
+ CConnman::Options options;
+ options.nMaxConnections = 125;
+ options.nMaxOutbound = nMaxOutbound;
+ options.nMaxFeeler = 1;
+
+ connman->Init(options);
+ std::vector<CNode *> vNodes;
+
+ // Mock some outbound peers
+ for (int i=0; i<nMaxOutbound; ++i) {
+ AddRandomOutboundPeer(vNodes, *peerLogic);
+ }
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+
+ // No nodes should be marked for disconnection while we have no extra peers
+ for (const CNode *node : vNodes) {
+ BOOST_CHECK(node->fDisconnect == false);
+ }
+
+ SetMockTime(GetTime() + 3*consensusParams.nPowTargetSpacing + 1);
+
+ // Now tip should definitely be stale, and we should look for an extra
+ // outbound peer
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ BOOST_CHECK(connman->GetTryNewOutboundPeer());
+
+ // Still no peers should be marked for disconnection
+ for (const CNode *node : vNodes) {
+ BOOST_CHECK(node->fDisconnect == false);
+ }
+
+ // If we add one more peer, something should get marked for eviction
+ // on the next check (since we're mocking the time to be in the future, the
+ // required time connected check should be satisfied).
+ AddRandomOutboundPeer(vNodes, *peerLogic);
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ for (int i=0; i<nMaxOutbound; ++i) {
+ BOOST_CHECK(vNodes[i]->fDisconnect == false);
+ }
+ // Last added node should get marked for eviction
+ BOOST_CHECK(vNodes.back()->fDisconnect == true);
+
+ vNodes.back()->fDisconnect = false;
+
+ // Update the last announced block time for the last
+ // peer, and check that the next newest node gets evicted.
+ UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ for (int i=0; i<nMaxOutbound-1; ++i) {
+ BOOST_CHECK(vNodes[i]->fDisconnect == false);
+ }
+ BOOST_CHECK(vNodes[nMaxOutbound-1]->fDisconnect == true);
+ BOOST_CHECK(vNodes.back()->fDisconnect == false);
+
+ bool dummy;
+ for (const CNode *node : vNodes) {
+ peerLogic->FinalizeNode(node->GetId(), dummy);
+ }
+
+ CConnmanTest::ClearNodes();
+}
+
BOOST_AUTO_TEST_CASE(DoS_banning)
{
std::atomic<bool> interruptDummy(false);
@@ -50,27 +183,42 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode1, *connman);
+ peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ }
+ LOCK(dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
dummyNode2.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode2, *connman);
+ peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1;
dummyNode2.fSuccessfullyConnected = true;
- Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode2.GetId(), 50);
+ }
+ LOCK(dummyNode2.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
- Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode2.GetId(), 50);
+ }
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr2));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
+ peerLogic->FinalizeNode(dummyNode2.GetId(), dummy);
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
@@ -82,19 +230,32 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode1, *connman);
+ peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 100);
+ }
+ LOCK(dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
- Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 10);
+ }
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
- Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 1);
+ }
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
@@ -108,12 +269,16 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress addr(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true);
dummyNode.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode, *connman);
+ peerLogic->InitializeNode(&dummyNode);
dummyNode.nVersion = 1;
dummyNode.fSuccessfullyConnected = true;
- Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode, *connman, interruptDummy);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode.GetId(), 100);
+ }
+ LOCK(dummyNode.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60);
@@ -121,11 +286,15 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime+60*60*24+1);
BOOST_CHECK(!connman->IsBanned(addr));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode.GetId(), dummy);
}
CTransactionRef RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
+ LOCK(cs_main);
it = mapOrphanTransactions.lower_bound(InsecureRand256());
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
@@ -195,6 +364,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
}
+ LOCK(cs_main);
// Test EraseOrphansFor:
for (NodeId i = 0; i < 3; i++)
{
diff --git a/src/test/README.md b/src/test/README.md
index eeb04c6ffa..01da32109b 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -5,7 +5,10 @@ and tests weren't explicitly disabled.
After configuring, they can be run with `make check`.
-To run the bitcoind tests manually, launch `src/test/test_bitcoin`.
+To run the bitcoind tests manually, launch `src/test/test_bitcoin`. To recompile
+after a test file was modified, run `make` and then run the test again. If you
+modify a non-test file, use `make -C src/test` to recompile only what's needed
+to run the bitcoind tests.
To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing
.cpp files in the `test/` directory or add new .cpp files that
@@ -49,4 +52,4 @@ 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/).
+[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://archive.is/dRBGf).
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 2ad22d34ad..609b1a05d3 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -1,21 +1,21 @@
// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrman.h"
-#include "test/test_bitcoin.h"
+#include <addrman.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include "hash.h"
-#include "netbase.h"
-#include "random.h"
+#include <hash.h>
+#include <netbase.h>
+#include <random.h>
class CAddrManTest : public CAddrMan
{
uint64_t state;
public:
- CAddrManTest(bool makeDeterministic = true)
+ explicit CAddrManTest(bool makeDeterministic = true)
{
state = 1;
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 4a533b5bf2..83fa3b76be 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
+#include <util.h>
-#include "support/allocators/secure.h"
-#include "test/test_bitcoin.h"
+#include <support/allocators/secure.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 952cf901f0..7ebbd22c5d 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "amount.h"
-#include "policy/feerate.h"
-#include "test/test_bitcoin.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 2c98fbcfd6..eb3148a1de 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -8,11 +8,11 @@
#include <iomanip>
#include <limits>
#include <cmath>
-#include "uint256.h"
-#include "arith_uint256.h"
+#include <uint256.h>
+#include <arith_uint256.h>
#include <string>
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <version.h>
+#include <test/test_bitcoin.h>
BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup)
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index 6422b3a88f..abf236b953 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index b33cdb9fe6..3156cc53d0 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -2,22 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
+#include <base58.h>
-#include "data/base58_encode_decode.json.h"
-#include "data/base58_keys_invalid.json.h"
-#include "data/base58_keys_valid.json.h"
+#include <test/data/base58_encode_decode.json.h>
+#include <test/data/base58_keys_invalid.json.h>
+#include <test/data/base58_keys_valid.json.h>
-#include "key.h"
-#include "script/script.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <key.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+
+#include <univalue.h>
#include <boost/test/unit_test.hpp>
-#include <univalue.h>
extern UniValue read_json(const std::string& jsondata);
@@ -72,63 +73,18 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
}
-// Visitor to check address type
-class TestAddrTypeVisitor : public boost::static_visitor<bool>
-{
-private:
- std::string exp_addrType;
-public:
- TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }
- bool operator()(const CKeyID &id) const
- {
- return (exp_addrType == "pubkey");
- }
- bool operator()(const CScriptID &id) const
- {
- return (exp_addrType == "script");
- }
- bool operator()(const CNoDestination &no) const
- {
- return (exp_addrType == "none");
- }
-};
-
-// Visitor to check address payload
-class TestPayloadVisitor : public boost::static_visitor<bool>
-{
-private:
- std::vector<unsigned char> exp_payload;
-public:
- TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }
- bool operator()(const CKeyID &id) const
- {
- uint160 exp_key(exp_payload);
- return exp_key == id;
- }
- bool operator()(const CScriptID &id) const
- {
- uint160 exp_key(exp_payload);
- return exp_key == id;
- }
- bool operator()(const CNoDestination &no) const
- {
- return exp_payload.size() == 0;
- }
-};
-
// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
SelectParams(CBaseChainParams::MAIN);
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
std::string strTest = test.write();
- if (test.size() < 3) // Allow for extra stuff (useful for comments)
- {
+ if (test.size() < 3) { // Allow for extra stuff (useful for comments)
BOOST_ERROR("Bad test: " << strTest);
continue;
}
@@ -136,16 +92,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
- bool isTestnet = find_value(metadata, "isTestnet").get_bool();
- if (isTestnet)
- SelectParams(CBaseChainParams::TESTNET);
- else
- SelectParams(CBaseChainParams::MAIN);
- if(isPrivkey)
- {
+ SelectParams(find_value(metadata, "chain").get_str());
+ bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool();
+ if (isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key
- // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
@@ -153,18 +104,29 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
- }
- else
- {
- std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
+ } else {
// Must be valid public key
- BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
- CTxDestination dest = addr.Get();
- BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
+ destination = DecodeDestination(exp_base58string);
+ CScript script = GetScriptForDestination(destination);
+ BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
+ BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
+
+ // Try flipped case version
+ for (char& c : exp_base58string) {
+ if (c >= 'a' && c <= 'z') {
+ c = (c - 'a') + 'A';
+ } else if (c >= 'A' && c <= 'Z') {
+ c = (c - 'A') + 'a';
+ }
+ }
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(IsValidDestination(destination) == try_case_flip, "!IsValid case flipped:" + strTest);
+ if (IsValidDestination(destination)) {
+ script = GetScriptForDestination(destination);
+ BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
+ }
// Public key must be invalid private key
secret.SetString(exp_base58string);
@@ -190,13 +152,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
- bool isTestnet = find_value(metadata, "isTestnet").get_bool();
- if (isTestnet)
- SelectParams(CBaseChainParams::TESTNET);
- else
- SelectParams(CBaseChainParams::MAIN);
- if(isPrivkey)
- {
+ SelectParams(find_value(metadata, "chain").get_str());
+ if (isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
@@ -204,48 +161,26 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CBitcoinSecret secret;
secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
- }
- else
- {
- std::string exp_addrType = find_value(metadata, "addrType").get_str();
+ } else {
CTxDestination dest;
- if(exp_addrType == "pubkey")
- {
- dest = CKeyID(uint160(exp_payload));
- }
- else if(exp_addrType == "script")
- {
- dest = CScriptID(uint160(exp_payload));
- }
- else if(exp_addrType == "none")
- {
- dest = CNoDestination();
- }
- else
- {
- BOOST_ERROR("Bad addrtype: " << strTest);
- continue;
- }
- CBitcoinAddress addrOut;
- BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
- BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
+ CScript exp_script(exp_payload.begin(), exp_payload.end());
+ ExtractDestination(exp_script, dest);
+ std::string address = EncodeDestination(dest);
+
+ BOOST_CHECK_EQUAL(address, exp_base58string);
}
}
- // Visiting a CNoDestination must fail
- CBitcoinAddress dummyAddr;
- CTxDestination nodest = CNoDestination();
- BOOST_CHECK(!dummyAddr.Set(nodest));
-
SelectParams(CBaseChainParams::MAIN);
}
+
// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -258,13 +193,15 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
- secret.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
+ for (auto chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) {
+ SelectParams(chain);
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
+ secret.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey in mainnet:" + strTest);
+ }
}
}
BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index ccad94d946..46b3a04f35 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
new file mode 100644
index 0000000000..495290c8d9
--- /dev/null
+++ b/src/test/bech32_tests.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bech32.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup)
+
+bool CaseInsensitiveEqual(const std::string &s1, const std::string &s2)
+{
+ if (s1.size() != s2.size()) return false;
+ for (size_t i = 0; i < s1.size(); ++i) {
+ char c1 = s1[i];
+ if (c1 >= 'A' && c1 <= 'Z') c1 -= ('A' - 'a');
+ char c2 = s2[i];
+ if (c2 >= 'A' && c2 <= 'Z') c2 -= ('A' - 'a');
+ if (c1 != c2) return false;
+ }
+ return true;
+}
+
+BOOST_AUTO_TEST_CASE(bip173_testvectors_valid)
+{
+ static const std::string CASES[] = {
+ "A12UEL5L",
+ "a12uel5l",
+ "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
+ "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
+ "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
+ "?1ezyfcl",
+ };
+ for (const std::string& str : CASES) {
+ auto ret = bech32::Decode(str);
+ BOOST_CHECK(!ret.first.empty());
+ std::string recode = bech32::Encode(ret.first, ret.second);
+ BOOST_CHECK(!recode.empty());
+ BOOST_CHECK(CaseInsensitiveEqual(str, recode));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid)
+{
+ static const std::string CASES[] = {
+ " 1nwldj5",
+ "\x7f""1axkwrx",
+ "\x80""1eym55h",
+ "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
+ "pzry9x0s0muk",
+ "1pzry9x0s0muk",
+ "x1b4n0q5v",
+ "li1dgmt3",
+ "de1lg7wt\xff",
+ "A1G7SGD8",
+ "10a06t8",
+ "1qzzfhee",
+ };
+ for (const std::string& str : CASES) {
+ auto ret = bech32::Decode(str);
+ BOOST_CHECK(ret.first.empty());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 6bcd550d7b..e3e727439b 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -4,12 +4,12 @@
#include <boost/test/unit_test.hpp>
-#include "base58.h"
-#include "key.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <base58.h>
+#include <key.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
@@ -24,7 +24,7 @@ struct TestVector {
std::string strHexMaster;
std::vector<TestDerivation> vDerive;
- TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
+ explicit TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {
vDerive.push_back(TestDerivation());
@@ -91,7 +91,7 @@ void RunTest(const TestVector &test) {
std::vector<unsigned char> seed = ParseHex(test.strHexMaster);
CExtKey key;
CExtPubKey pubkey;
- key.SetMaster(&seed[0], seed.size());
+ key.SetMaster(seed.data(), seed.size());
pubkey = key.Neuter();
for (const TestDerivation &derive : test.vDerive) {
unsigned char data[74];
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 10a40fea3c..718b5bdfb9 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "blockencodings.h"
-#include "consensus/merkle.h"
-#include "chainparams.h"
-#include "random.h"
+#include <blockencodings.h>
+#include <consensus/merkle.h>
+#include <chainparams.h>
+#include <random.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
@@ -51,7 +51,7 @@ static CBlock BuildBlockTestCase() {
return block;
}
-// Number of shared use_counts we expect for a tx we havent touched
+// Number of shared use_counts we expect for a tx we haven't touched
// == 2 (mempool + our copy from the GetSharedTx call)
#define SHARED_TX_OFFSET 2
@@ -62,6 +62,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
// Do a simple ShortTxIDs RT
@@ -118,12 +119,12 @@ public:
std::vector<uint64_t> shorttxids;
std::vector<PrefilledTransaction> prefilledtxn;
- TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
+ explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << orig;
stream >> *this;
}
- TestHeaderAndShortIDs(const CBlock& block) :
+ explicit TestHeaderAndShortIDs(const CBlock& block) :
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}
uint64_t GetShortID(const uint256& txhash) const {
@@ -161,6 +162,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash;
@@ -227,6 +229,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 2085b5cb2b..fdd30be0b1 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -2,19 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bloom.h"
-
-#include "base58.h"
-#include "clientversion.h"
-#include "key.h"
-#include "merkleblock.h"
-#include "random.h"
-#include "serialize.h"
-#include "streams.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <bloom.h>
+
+#include <base58.h>
+#include <clientversion.h>
+#include <key.h>
+#include <merkleblock.h>
+#include <primitives/block.h>
+#include <random.h>
+#include <serialize.h>
+#include <streams.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
@@ -154,8 +155,8 @@ BOOST_AUTO_TEST_CASE(bloom_match)
COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
{
std::vector<unsigned char> data(32 + sizeof(unsigned int));
- memcpy(&data[0], prevOutPoint.hash.begin(), 32);
- memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
+ memcpy(data.data(), prevOutPoint.hash.begin(), 32);
+ memcpy(data.data()+32, &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data);
}
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
@@ -179,20 +180,15 @@ BOOST_AUTO_TEST_CASE(bloom_match)
BOOST_AUTO_TEST_CASE(merkle_block_1)
{
- // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
- // With 9 txes
- CBlock block;
- CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
- stream >> block;
-
+ CBlock block = getBlock13b8a();
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
// Match the last transaction
filter.insert(uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
CMerkleBlock merkleBlock(block, filter);
- BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
- BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 1);
std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
index 7b3134d327..ab4f08b999 100644
--- a/src/test/bswap_tests.cpp
+++ b/src/test/bswap_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compat/byteswap.h"
-#include "test/test_bitcoin.h"
+#include <compat/byteswap.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 6ae0bcadd0..42f9dd0600 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
-#include "utiltime.h"
-#include "validation.h"
+#include <util.h>
+#include <utiltime.h>
+#include <validation.h>
-#include "test/test_bitcoin.h"
-#include "checkqueue.h"
+#include <test/test_bitcoin.h>
+#include <checkqueue.h>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
#include <atomic>
@@ -18,13 +18,13 @@
#include <unordered_set>
#include <memory>
-#include "random.h"
+#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;
+static const unsigned int QUEUE_BATCH_SIZE = 128;
struct FakeCheck {
bool operator()()
@@ -38,7 +38,7 @@ struct FakeCheckCheckCompletion {
static std::atomic<size_t> n_calls;
bool operator()()
{
- ++n_calls;
+ n_calls.fetch_add(1, std::memory_order_relaxed);
return true;
}
void swap(FakeCheckCheckCompletion& x){};
@@ -88,15 +88,15 @@ struct MemoryCheck {
//
// Really, copy constructor should be deletable, but CCheckQueue breaks
// if it is deleted because of internal push_back.
- fake_allocated_memory += b;
+ fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);
};
MemoryCheck(bool b_) : b(b_)
{
- fake_allocated_memory += b;
+ fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);
};
- ~MemoryCheck(){
- fake_allocated_memory -= b;
-
+ ~MemoryCheck()
+ {
+ fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);
};
void swap(MemoryCheck& x) { std::swap(b, x.b); };
};
@@ -117,9 +117,9 @@ struct FrozenCleanupCheck {
{
if (should_freeze) {
std::unique_lock<std::mutex> l(m);
- nFrozen = 1;
+ nFrozen.store(1, std::memory_order_relaxed);
cv.notify_one();
- cv.wait(l, []{ return nFrozen == 0;});
+ cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});
}
}
void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};
@@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
control.Add(vChecks);
}
bool r =control.Wait();
- BOOST_REQUIRE(r || end_fails);
+ BOOST_REQUIRE(r != end_fails);
}
}
tg.interrupt_all();
@@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
tg.join_all();
}
-// Test that a new verification cannot occur until all checks
+// Test that a new verification cannot occur until all checks
// have been destructed
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
{
@@ -361,11 +361,14 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
// Wait until the queue has finished all jobs and frozen
FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});
- // Try to get control of the queue a bunch of times
- for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
- }
- // Unfreeze
+ }
+ // Try to get control of the queue a bunch of times
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ {
+ // Unfreeze (we need lock n case of spurious wakeup)
+ std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
FrozenCleanupCheck::nFrozen = 0;
}
// Awaken frozen destructor
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index e24431528a..ed556c07f4 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coins.h"
-#include "script/standard.h"
-#include "uint256.h"
-#include "undo.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "consensus/validation.h"
+#include <coins.h>
+#include <script/standard.h>
+#include <uint256.h>
+#include <undo.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <consensus/validation.h>
#include <vector>
#include <map>
@@ -74,23 +74,23 @@ public:
class CCoinsViewCacheTest : public CCoinsViewCache
{
public:
- CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}
+ explicit CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}
void SelfTest() const
{
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins);
size_t count = 0;
- for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
- ret += it->second.coin.DynamicMemoryUsage();
+ for (const auto& entry : cacheCoins) {
+ ret += entry.second.coin.DynamicMemoryUsage();
++count;
}
BOOST_CHECK_EQUAL(GetCacheSize(), count);
BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
}
- CCoinsMap& map() { return cacheCoins; }
- size_t& usage() { return cachedCoinsUsage; }
+ CCoinsMap& map() const { return cacheCoins; }
+ size_t& usage() const { return cachedCoinsUsage; }
};
} // namespace
@@ -189,15 +189,15 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
// Once every 1000 iterations and at the end, verify the full cache.
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (auto it = result.begin(); it != result.end(); it++) {
- bool have = stack.back()->HaveCoin(it->first);
- const Coin& coin = stack.back()->AccessCoin(it->first);
+ for (const auto& entry : result) {
+ bool have = stack.back()->HaveCoin(entry.first);
+ const Coin& coin = stack.back()->AccessCoin(entry.first);
BOOST_CHECK(have == !coin.IsSpent());
- BOOST_CHECK(coin == it->second);
+ BOOST_CHECK(coin == entry.second);
if (coin.IsSpent()) {
missed_an_entry = true;
} else {
- BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));
+ BOOST_CHECK(stack.back()->HaveCoinInCache(entry.first));
found_an_entry = true;
}
}
@@ -275,7 +275,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
// except the emphasis is on testing the functionality of UpdateCoins
// random txs are created and UpdateCoins is used to update the cache stack
// In particular it is tested that spending a duplicate coinbase tx
-// has the expected effect (the other duplicate is overwitten at all cache levels)
+// has the expected effect (the other duplicate is overwritten at all cache levels)
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
{
bool spent_a_duplicate_coinbase = false;
@@ -420,11 +420,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Once every 1000 iterations and at the end, verify the full cache.
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (auto it = result.begin(); it != result.end(); it++) {
- bool have = stack.back()->HaveCoin(it->first);
- const Coin& coin = stack.back()->AccessCoin(it->first);
+ for (const auto& entry : result) {
+ bool have = stack.back()->HaveCoin(entry.first);
+ const Coin& coin = stack.back()->AccessCoin(entry.first);
BOOST_CHECK(have == !coin.IsSpent());
- BOOST_CHECK(coin == it->second);
+ BOOST_CHECK(coin == entry.second);
}
}
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index 35e4458bba..87e75d8020 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compressor.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <compressor.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 391ad14ffa..125b68e76d 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/aes.h"
-#include "crypto/chacha20.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/sha512.h"
-#include "crypto/hmac_sha256.h"
-#include "crypto/hmac_sha512.h"
-#include "random.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <crypto/aes.h>
+#include <crypto/chacha20.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <crypto/sha512.h>
+#include <crypto/hmac_sha256.h>
+#include <crypto/hmac_sha512.h>
+#include <random.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
@@ -58,12 +58,12 @@ void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVecto
void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {
std::vector<unsigned char> key = ParseHex(hexkey);
- TestVector(CHMAC_SHA256(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
+ TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));
}
void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {
std::vector<unsigned char> key = ParseHex(hexkey);
- TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
+ TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));
}
void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
@@ -76,13 +76,13 @@ void TestAES128(const std::string &hexkey, const std::string &hexin, const std::
assert(key.size() == 16);
assert(in.size() == 16);
assert(correctout.size() == 16);
- AES128Encrypt enc(&key[0]);
+ AES128Encrypt enc(key.data());
buf.resize(correctout.size());
buf2.resize(correctout.size());
- enc.Encrypt(&buf[0], &in[0]);
+ enc.Encrypt(buf.data(), in.data());
BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));
- AES128Decrypt dec(&key[0]);
- dec.Decrypt(&buf2[0], &buf[0]);
+ AES128Decrypt dec(key.data());
+ dec.Decrypt(buf2.data(), buf.data());
BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));
}
@@ -96,12 +96,12 @@ void TestAES256(const std::string &hexkey, const std::string &hexin, const std::
assert(key.size() == 32);
assert(in.size() == 16);
assert(correctout.size() == 16);
- AES256Encrypt enc(&key[0]);
+ AES256Encrypt enc(key.data());
buf.resize(correctout.size());
- enc.Encrypt(&buf[0], &in[0]);
+ enc.Encrypt(buf.data(), in.data());
BOOST_CHECK(buf == correctout);
- AES256Decrypt dec(&key[0]);
- dec.Decrypt(&buf[0], &buf[0]);
+ AES256Decrypt dec(key.data());
+ dec.Decrypt(buf.data(), buf.data());
BOOST_CHECK(buf == in);
}
@@ -114,16 +114,16 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad
std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
// Encrypt the plaintext and verify that it equals the cipher
- AES128CBCEncrypt enc(&key[0], &iv[0], pad);
- int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ AES128CBCEncrypt enc(key.data(), iv.data(), pad);
+ int size = enc.Encrypt(in.data(), in.size(), realout.data());
realout.resize(size);
BOOST_CHECK(realout.size() == correctout.size());
BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
// Decrypt the cipher and verify that it equals the plaintext
std::vector<unsigned char> decrypted(correctout.size());
- AES128CBCDecrypt dec(&key[0], &iv[0], pad);
- size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ AES128CBCDecrypt dec(key.data(), iv.data(), pad);
+ size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data());
decrypted.resize(size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
@@ -133,12 +133,12 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad
{
std::vector<unsigned char> sub(i, in.end());
std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
- int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ int _size = enc.Encrypt(sub.data(), sub.size(), subout.data());
if (_size != 0)
{
subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data());
subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
@@ -155,16 +155,16 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
// Encrypt the plaintext and verify that it equals the cipher
- AES256CBCEncrypt enc(&key[0], &iv[0], pad);
- int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ AES256CBCEncrypt enc(key.data(), iv.data(), pad);
+ int size = enc.Encrypt(in.data(), in.size(), realout.data());
realout.resize(size);
BOOST_CHECK(realout.size() == correctout.size());
BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
// Decrypt the cipher and verify that it equals the plaintext
std::vector<unsigned char> decrypted(correctout.size());
- AES256CBCDecrypt dec(&key[0], &iv[0], pad);
- size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ AES256CBCDecrypt dec(key.data(), iv.data(), pad);
+ size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data());
decrypted.resize(size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
@@ -174,12 +174,12 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
{
std::vector<unsigned char> sub(i, in.end());
std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
- int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ int _size = enc.Encrypt(sub.data(), sub.size(), subout.data());
if (_size != 0)
{
subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data());
subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
@@ -340,6 +340,22 @@ BOOST_AUTO_TEST_CASE(hmac_sha256_testvectors) {
"647320746f20626520686173686564206265666f7265206265696e6720757365"
"642062792074686520484d414320616c676f726974686d2e",
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2");
+ // Test case with key length 63 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "9de4b546756c83516720a4ad7fe7bdbeac4298c6fdd82b15f895a6d10b0769a6");
+ // Test case with key length 64 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "528c609a4c9254c274585334946b7c2661bad8f1fc406b20f6892478d19163dd");
+ // Test case with key length 65 bytes.
+ TestHMACSHA256("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "d06af337f359a2330deffb8e3cbe4b5b7aa8ca1f208528cdbd245d5dc63c4483");
}
BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
@@ -383,6 +399,31 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
"642062792074686520484d414320616c676f726974686d2e",
"e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
+ // Test case with key length 127 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "267424dfb8eeb999f3e5ec39a4fe9fd14c923e6187e0897063e5c9e02b2e624a"
+ "c04413e762977df71a9fb5d562b37f89dfdfb930fce2ed1fa783bbc2a203d80e");
+ // Test case with key length 128 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "43aaac07bb1dd97c82c04df921f83b16a68d76815cd1a30d3455ad43a3d80484"
+ "2bb35462be42cc2e4b5902de4d204c1c66d93b47d1383e3e13a3788687d61258");
+ // Test case with key length 129 bytes.
+ TestHMACSHA512("4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"
+ "4a",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "0b273325191cfc1b4b71d5075c8fcad67696309d292b1dad2cd23983a35feb8e"
+ "fb29795e79f2ef27f68cb1e16d76178c307a67beaad9456fac5fdffeadb16e2c");
}
BOOST_AUTO_TEST_CASE(aes_testvectors) {
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 1004482224..32d46da984 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
-#include "cuckoocache.h"
-#include "script/sigcache.h"
-#include "test/test_bitcoin.h"
-#include "random.h"
+#include <cuckoocache.h>
+#include <script/sigcache.h>
+#include <test/test_bitcoin.h>
+#include <random.h>
#include <thread>
/** Test Suite for CuckooCache
diff --git a/src/test/data/base58_keys_invalid.json b/src/test/data/base58_keys_invalid.json
index a088620f1b..2056c7491c 100644
--- a/src/test/data/base58_keys_invalid.json
+++ b/src/test/data/base58_keys_invalid.json
@@ -148,5 +148,35 @@
],
[
"2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"
+ ],
+ [
+ "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty"
+ ],
+ [
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5"
+ ],
+ [
+ "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2"
+ ],
+ [
+ "bc1rw5uspcuh"
+ ],
+ [
+ "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90"
+ ],
+ [
+ "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P"
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7"
+ ],
+ [
+ "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du"
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv"
+ ],
+ [
+ "bc1gmk9yu"
]
]
diff --git a/src/test/data/base58_keys_valid.json b/src/test/data/base58_keys_valid.json
index e1e252e22d..8418a6002d 100644
--- a/src/test/data/base58_keys_valid.json
+++ b/src/test/data/base58_keys_valid.json
@@ -1,452 +1,533 @@
[
[
- "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
- "65a16059864a2fdbc7c99a4723a8395bc6f188eb",
+ "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
+ "76a91465a16059864a2fdbc7c99a4723a8395bc6f188eb88ac",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
- "74f209f6ea907e2ea48f74fae05782ae8a665257",
+ "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
+ "a91474f209f6ea907e2ea48f74fae05782ae8a66525787",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
- "53c0307d6851aa0ce7825ba883c6bd9ad242b486",
+ "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
+ "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
- "6349a418fc4578d10a372b54b45c280cc8c4382f",
+ "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
+ "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "regtest"
}
- ],
+ ],
[
- "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
- "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
+ "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
+ "a9146349a418fc4578d10a372b54b45c280cc8c4382f87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
- "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
+ "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
+ "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
- "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
+ "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
+ "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
- "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
+ "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
+ "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
- "6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
+ "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
+ "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
- "fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
+ "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
+ "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
- "f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
+ "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
+ "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
- "c579342c2c4c9220205e2cdc285617040c924a0a",
+ "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
+ "76a9146d23156cbbdcc82a5a47eee4c2c7c583c18b6bf488ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
- "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
+ "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
+ "a914fcc5460dd6e2487c7d75b1963625da0e8f4c597587",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
- "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
+ "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
+ "76a914f1d470f9b02370fdec2e6b708b08ac431bf7a5f788ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
- "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
+ "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
+ "a914c579342c2c4c9220205e2cdc285617040c924a0a87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
- "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
+ "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
+ "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
- "7987ccaa53d02c8873487ef919677cd3db7a6912",
+ "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
+ "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
- "63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
+ "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
+ "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
- "ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
+ "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
+ "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
- "c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
+ "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
+ "76a9147987ccaa53d02c8873487ef919677cd3db7a691288ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
- "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
+ "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
+ "a91463bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
- "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
+ "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
+ "76a914ef66444b5b17f14e8fae6e7e19b045a78c54fd7988ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
- "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
+ "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
+ "a914c3e55fceceaa4391ed2a9677f4a4d34eacd021a087",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
- "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
+ "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
+ "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
- "adc1cc2081a27206fae25792f28bbc55b831549d",
+ "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
+ "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
- "188f91a931947eddd7432d6e614387e32b244709",
+ "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
+ "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
- "1694f5bc1a7295b600f40018a618a6ea48eeb498",
+ "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
+ "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
- "3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
+ "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
+ "76a914adc1cc2081a27206fae25792f28bbc55b831549d88ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
- "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
+ "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
+ "a914188f91a931947eddd7432d6e614387e32b24470987",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
- "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
+ "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
+ "76a9141694f5bc1a7295b600f40018a618a6ea48eeb49888ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
- "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
+ "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
+ "a9143b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f387",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
- "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
+ "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
+ "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
- "c4c1b72491ede1eedaca00618407ee0b772cad0d",
+ "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
+ "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
- "f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
+ "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
+ "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
- "261f83568a098a8638844bd7aeca039d5f2352c0",
+ "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
+ "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
- "e930e1834a4d234702773951d627cce82fbb5d2e",
+ "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
+ "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
- "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
+ "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
+ "76a914c4c1b72491ede1eedaca00618407ee0b772cad0d88ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
- "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
+ "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
+ "a914f6fe69bcb548a829cce4c57bf6fff8af3a5981f987",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
- "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
+ "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
+ "76a914261f83568a098a8638844bd7aeca039d5f2352c088ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
- "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
+ "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
+ "a914e930e1834a4d234702773951d627cce82fbb5d2e87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
- "5eadaf9bb7121f0f192561a5a62f5e5f54210292",
+ "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
+ "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
- "3f210e7277c899c3a155cc1c90f4106cbddeec6e",
+ "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
+ "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
- "c8a3c2a09a298592c3e180f02487cd91ba3400b5",
+ "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
+ "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
- "99b31df7c9068d1481b596578ddbb4d3bd90baeb",
+ "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
+ "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
- "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
+ "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
+ "76a9145eadaf9bb7121f0f192561a5a62f5e5f5421029288ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
- "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
+ "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
+ "a9143f210e7277c899c3a155cc1c90f4106cbddeec6e87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
- "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
+ "76a914c8a3c2a09a298592c3e180f02487cd91ba3400b588ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
- "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
+ "a91499b31df7c9068d1481b596578ddbb4d3bd90baeb87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
- "1ed467017f043e91ed4c44b4e8dd674db211c4e6",
+ "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
+ "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
- "5ece0cadddc415b1980f001785947120acdb36fc",
+ "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
+ "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
+ }
+ ],
+ [
+ "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
+ "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
+ }
+ ],
+ [
+ "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
+ "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
+ }
+ ],
+ [
+ "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
+ "76a9141ed467017f043e91ed4c44b4e8dd674db211c4e688ac",
+ {
+ "isPrivkey": false,
+ "chain": "main"
+ }
+ ],
+ [
+ "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
+ "a9145ece0cadddc415b1980f001785947120acdb36fc87",
+ {
+ "isPrivkey": false,
+ "chain": "main"
+ }
+ ],
+ [
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
+ "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080",
+ "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "regtest",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
+ "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ {
+ "isPrivkey": false,
+ "chain": "test",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
+ "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1sw50qa3jx3s",
+ "6002751e",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
+ "5210751e76e8199196d454941c45d1b3a323",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ {
+ "isPrivkey": false,
+ "chain": "test",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7",
+ "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ {
+ "isPrivkey": false,
+ "chain": "regtest",
+ "tryCaseFlip": true
}
]
]
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 698e898231..63f43c0fc6 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -862,8 +862,6 @@
["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "CHECKSEQUENCEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 2235bd0ae7..09442b7f9f 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -205,7 +205,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
-["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"],
+["By-time locks, with argument just beyond txin.nSequence (but within numerical boundaries)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index e6b382af13..ad74b7cf1b 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -45,7 +45,7 @@
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
-["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
+["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation. In a signature, it contains an ASN1 integer which isn't strict-DER conformant due to being negative, which doesn't make sense in a signature. Before BIP66 activated, it was a valid signature. After it activated, it's not valid any more."],
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 6ed6e7744e..2e1e4da72f 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "dbwrapper.h"
-#include "uint256.h"
-#include "random.h"
-#include "test/test_bitcoin.h"
+#include <dbwrapper.h>
+#include <uint256.h>
+#include <random.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
@@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
@@ -135,8 +135,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK
- delete dbw;
- dbw = nullptr;
+ dbw.reset();
// Now, set up another wrapper that wants to obfuscate the same directory
CDBWrapper odbw(ph, (1 << 10), false, false, true);
@@ -167,7 +166,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
@@ -177,8 +176,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK
- delete dbw;
- dbw = nullptr;
+ dbw.reset();
// Simulate a -reindex by wiping the existing data store
CDBWrapper odbw(ph, (1 << 10), false, true, true);
@@ -204,19 +202,31 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
uint32_t value = x*x;
- BOOST_CHECK(dbw.Write(key, value));
+ if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value));
}
+ // Check that creating an iterator creates a snapshot
std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
+
+ for (int x=0x00; x<256; ++x) {
+ uint8_t key = x;
+ uint32_t value = x*x;
+ if (x & 1) BOOST_CHECK(dbw.Write(key, value));
+ }
+
for (int seek_start : {0x00, 0x80}) {
it->Seek((uint8_t)seek_start);
- for (int x=seek_start; x<256; ++x) {
+ for (int x=seek_start; x<255; ++x) {
uint8_t key;
uint32_t value;
BOOST_CHECK(it->Valid());
if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
break;
BOOST_CHECK(it->GetKey(key));
+ if (x & 1) {
+ BOOST_CHECK_EQUAL(key, x + 1);
+ continue;
+ }
BOOST_CHECK(it->GetValue(value));
BOOST_CHECK_EQUAL(key, x);
BOOST_CHECK_EQUAL(value, x*x);
@@ -231,7 +241,7 @@ struct StringContentsSerializer {
// This is a terrible idea
std::string str;
StringContentsSerializer() {}
- StringContentsSerializer(const std::string& inp) : str(inp) {}
+ explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
StringContentsSerializer& operator+=(const std::string& s) {
str += s;
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 18a7e59933..3c39258693 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
@@ -27,7 +27,7 @@ static void ResetArgs(const std::string& strArg)
for (std::string& s : vecArg)
vecChar.push_back(s.c_str());
- gArgs.ParseParameters(vecChar.size(), &vecChar[0]);
+ gArgs.ParseParameters(vecChar.size(), vecChar.data());
}
BOOST_AUTO_TEST_CASE(boolarg)
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 05b6b3b1e6..68f445d142 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "hash.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <hash.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 559b3caf1c..7b9d7a6398 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -2,31 +2,30 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
+#include <key.h>
-#include "base58.h"
-#include "script/script.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <base58.h>
+#include <script/script.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
#include <boost/test/unit_test.hpp>
-static const std::string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
-static const std::string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
-static const std::string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
-static const std::string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
-static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
-static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
-static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
-static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
+static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
+static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
+static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
+static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
+static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
+static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
+static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
+static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
-
-static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
+static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
@@ -74,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
- BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
- BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
- BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
- BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
for (int n=0; n<16; n++)
{
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index b071ab117b..90730cd7b5 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "limitedmap.h"
+#include <limitedmap.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 656aec606b..4be32f7628 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "validation.h"
-#include "net.h"
+#include <chainparams.h>
+#include <validation.h>
+#include <net.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 51b28d09fa..a694b870fe 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/policy.h"
-#include "txmempool.h"
-#include "util.h"
+#include <policy/policy.h>
+#include <txmempool.h>
+#include <util.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <list>
@@ -165,6 +165,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
sortedOrder[3] = tx4.GetHash().ToString(); // 15000
sortedOrder[4] = tx2.GetHash().ToString(); // 20000
+ LOCK(pool.cs);
CheckSort<descendant_score>(pool, sortedOrder);
/* low fee but with high fee child */
@@ -375,6 +376,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
}
sortedOrder[4] = tx3.GetHash().ToString(); // 0
+ LOCK(pool.cs);
CheckSort<ancestor_score>(pool, sortedOrder);
/* low fee parent with high fee child */
@@ -559,15 +561,15 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
// ... we should keep the same min fee until we get a block
pool.removeForBlock(vtx, 1);
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
- BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
// ... then feerate should drop 1/2 each halflife
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
- BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
// ... with a 1/2 halflife when mempool is < 1/2 its target size
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
- BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
// ... with a 1/4 halflife when mempool is < 1/4 its target size
SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 1a1cf4399c..ee48d96ad9 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/merkle.h"
-#include "test/test_bitcoin.h"
+#include <consensus/merkle.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp
new file mode 100644
index 0000000000..37a1a84136
--- /dev/null
+++ b/src/test/merkleblock_tests.cpp
@@ -0,0 +1,78 @@
+// 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 <merkleblock.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(merkleblock_tests, BasicTestingSetup)
+
+/**
+ * Create a CMerkleBlock using a list of txids which will be found in the
+ * given block.
+ */
+BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_found)
+{
+ CBlock block = getBlock13b8a();
+
+ std::set<uint256> txids;
+
+ // Last txn in block.
+ uint256 txhash1 = uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20");
+
+ // Second txn in block.
+ uint256 txhash2 = uint256S("0xf9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07");
+
+ txids.insert(txhash1);
+ txids.insert(txhash2);
+
+ CMerkleBlock merkleBlock(block, txids);
+
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
+
+ // vMatchedTxn is only used when bloom filter is specified.
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 0);
+
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
+
+ BOOST_CHECK_EQUAL(merkleBlock.txn.ExtractMatches(vMatched, vIndex).GetHex(), block.hashMerkleRoot.GetHex());
+ BOOST_CHECK_EQUAL(vMatched.size(), 2);
+
+ // Ordered by occurrence in depth-first tree traversal.
+ BOOST_CHECK_EQUAL(vMatched[0].ToString(), txhash2.ToString());
+ BOOST_CHECK_EQUAL(vIndex[0], 1);
+
+ BOOST_CHECK_EQUAL(vMatched[1].ToString(), txhash1.ToString());
+ BOOST_CHECK_EQUAL(vIndex[1], 8);
+}
+
+
+/**
+ * Create a CMerkleBlock using a list of txids which will not be found in the
+ * given block.
+ */
+BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_not_found)
+{
+ CBlock block = getBlock13b8a();
+
+ std::set<uint256> txids2;
+ txids2.insert(uint256S("0xc0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
+ CMerkleBlock merkleBlock(block, txids2);
+
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 0);
+
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
+
+ BOOST_CHECK_EQUAL(merkleBlock.txn.ExtractMatches(vMatched, vIndex).GetHex(), block.hashMerkleRoot.GetHex());
+ BOOST_CHECK_EQUAL(vMatched.size(), 0);
+ BOOST_CHECK_EQUAL(vIndex.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9fa9a8509c..b1a2032ea8 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "consensus/merkle.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "miner.h"
-#include "policy/policy.h"
-#include "pubkey.h"
-#include "script/standard.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include "test/test_bitcoin.h"
+#include <chainparams.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <consensus/merkle.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <miner.h>
+#include <policy/policy.h>
+#include <pubkey.h>
+#include <script/standard.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+
+#include <test/test_bitcoin.h>
#include <memory>
@@ -32,7 +32,6 @@ static BlockAssembler AssemblerForTest(const CChainParams& params) {
BlockAssembler::Options options;
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
- options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
options.blockMinFeeRate = blockMinFeeRate;
return BlockAssembler(params, options);
}
@@ -336,23 +335,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
- // invalid (pre-p2sh) txn in mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
- script = CScript() << OP_0;
- tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
- hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
- mempool.clear();
-
// double spend txn pair in mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].scriptSig = CScript() << OP_1;
@@ -392,6 +374,24 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.SetTip(next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+
+ // invalid p2sh txn in mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
+ script = CScript() << OP_0;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ mempool.clear();
+
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex* del = chainActive.Tip();
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 5e89ef60d2..ffba7d6d22 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -2,22 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/interpreter.h"
-#include "script/sign.h"
-#include "script/ismine.h"
-#include "uint256.h"
-#include "test/test_bitcoin.h"
+#include <key.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/interpreter.h>
+#include <script/sign.h>
+#include <script/ismine.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
-typedef std::vector<unsigned char> valtype;
-
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
@@ -173,95 +171,6 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
BOOST_CHECK(!::IsStandard(malformed[i], whichType));
}
-BOOST_AUTO_TEST_CASE(multisig_Solver1)
-{
- // Tests Solver() that returns lists of keys that are
- // required to satisfy a ScriptPubKey
- //
- // Also tests IsMine() and ExtractDestination()
- //
- // Note: ExtractDestination for the multisignature transactions
- // always returns false for this release, even if you have
- // one key that would satisfy an (a|b) or 2-of-3 keys needed
- // to spend an escrow transaction.
- //
- CBasicKeyStore keystore, emptykeystore, partialkeystore;
- CKey key[3];
- CTxDestination keyaddr[3];
- for (int i = 0; i < 3; i++)
- {
- key[i].MakeNewKey(true);
- keystore.AddKey(key[i]);
- keyaddr[i] = key[i].GetPubKey().GetID();
- }
- partialkeystore.AddKey(key[0]);
-
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 1);
- CTxDestination addr;
- BOOST_CHECK(ExtractDestination(s, addr));
- BOOST_CHECK(addr == keyaddr[0]);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 1);
- CTxDestination addr;
- BOOST_CHECK(ExtractDestination(s, addr));
- BOOST_CHECK(addr == keyaddr[0]);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(solutions.size(), 4U);
- CTxDestination addr;
- BOOST_CHECK(!ExtractDestination(s, addr));
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- BOOST_CHECK(!IsMine(partialkeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(solutions.size(), 4U);
- std::vector<CTxDestination> addrs;
- int nRequired;
- BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
- BOOST_CHECK(addrs[0] == keyaddr[0]);
- BOOST_CHECK(addrs[1] == keyaddr[1]);
- BOOST_CHECK(nRequired == 1);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- BOOST_CHECK(!IsMine(partialkeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 5);
- }
-}
-
BOOST_AUTO_TEST_CASE(multisig_Sign)
{
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 31b05d868b..b4176a2b85 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,17 +1,17 @@
// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrman.h"
-#include "test/test_bitcoin.h"
+#include <addrman.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include "hash.h"
-#include "serialize.h"
-#include "streams.h"
-#include "net.h"
-#include "netbase.h"
-#include "chainparams.h"
-#include "util.h"
+#include <hash.h>
+#include <serialize.h>
+#include <streams.h>
+#include <net.h>
+#include <netbase.h>
+#include <chainparams.h>
+#include <util.h>
class CAddrManSerializationMock : public CAddrMan
{
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 1baf7643e5..f3a9b1fc65 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "netbase.h"
-#include "test/test_bitcoin.h"
-#include "utilstrencodings.h"
+#include <netbase.h>
+#include <test/test_bitcoin.h>
+#include <utilstrencodings.h>
#include <string>
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index c1d216d094..b7b632be3a 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/merkle.h"
-#include "merkleblock.h"
-#include "serialize.h"
-#include "streams.h"
-#include "uint256.h"
-#include "arith_uint256.h"
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <consensus/merkle.h>
+#include <merkleblock.h>
+#include <serialize.h>
+#include <streams.h>
+#include <uint256.h>
+#include <arith_uint256.h>
+#include <version.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index fd8f7191f4..d8026e4468 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/policy.h"
-#include "policy/fees.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "util.h"
+#include <policy/policy.h>
+#include <policy/fees.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <util.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index b13f2625aa..2837537c9a 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "pow.h"
-#include "random.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <pow.h>
+#include <random.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 345c4a2148..1327d67650 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -3,13 +3,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <vector>
-#include "prevector.h"
+#include <prevector.h>
-#include "reverse_iterator.h"
-#include "serialize.h"
-#include "streams.h"
+#include <reverse_iterator.h>
+#include <serialize.h>
+#include <streams.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
@@ -152,11 +152,11 @@ public:
pre_vector.assign(n, value);
}
- Size size() {
+ Size size() const {
return real_vector.size();
}
- Size capacity() {
+ Size capacity() const {
return pre_vector.capacity();
}
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 0d541ec7d4..781b1e242d 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -10,9 +10,9 @@
#include <map>
#include <stdlib.h>
-#include "support/events.h"
+#include <support/events.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 132e190051..1ca5a53d72 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
+#include <random.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index 00dc47e13e..86d6161e20 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "reverselock.h"
-#include "test/test_bitcoin.h"
+#include <reverselock.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index c6643be7a7..710d09ead6 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
-#include "rpc/client.h"
+#include <rpc/server.h>
+#include <rpc/client.h>
-#include "base58.h"
-#include "core_io.h"
-#include "netbase.h"
+#include <base58.h>
+#include <core_io.h>
+#include <netbase.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 51f9e9f39f..b3ec6d34c7 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compat/sanity.h"
-#include "key.h"
-#include "test/test_bitcoin.h"
+#include <compat/sanity.h>
+#include <key.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 1de865776e..7e86eed1c5 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
-#include "scheduler.h"
+#include <random.h>
+#include <scheduler.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index efd0f77d9f..5a64aa3959 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "script/ismine.h"
-#include "test/test_bitcoin.h"
+#include <consensus/tx_verify.h>
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <script/ismine.h>
+#include <test/test_bitcoin.h>
#include <vector>
@@ -112,8 +112,7 @@ BOOST_AUTO_TEST_CASE(sign)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- const CTxOut& output = txFrom.vout[txTo[i].vin[0].prevout.n];
- bool sigOK = CScriptCheck(output.scriptPubKey, output.nValue, txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
+ bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
new file mode 100644
index 0000000000..19060eccc9
--- /dev/null
+++ b/src/test/script_standard_tests.cpp
@@ -0,0 +1,741 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <key.h>
+#include <keystore.h>
+#include <script/ismine.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/standard.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<std::vector<unsigned char> > solutions;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_1 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(solutions.size(), 4);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
+ BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
+ BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
+ BOOST_CHECK(solutions[3] == std::vector<unsigned char>({2}));
+
+ s.clear();
+ s << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ ToByteVector(pubkeys[2]) <<
+ OP_3 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(solutions.size(), 5);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
+ BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
+ BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
+ BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2]));
+ BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3}));
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN <<
+ std::vector<unsigned char>({0}) <<
+ std::vector<unsigned char>({75}) <<
+ std::vector<unsigned char>({255});
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA);
+ BOOST_CHECK_EQUAL(solutions.size(), 0);
+
+ // TX_WITNESS_V0_KEYHASH
+ s.clear();
+ s << OP_0 << ToByteVector(pubkeys[0].GetID());
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
+
+ // TX_WITNESS_V0_SCRIPTHASH
+ uint256 scriptHash;
+ CSHA256().Write(&redeemScript[0], redeemScript.size())
+ .Finalize(scriptHash.begin());
+
+ s.clear();
+ s << OP_0 << ToByteVector(scriptHash);
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
+
+ // TX_NONSTANDARD
+ s.clear();
+ s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
+{
+ CKey key;
+ CPubKey pubkey;
+ key.MakeNewKey(true);
+ pubkey = key.GetPubKey();
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<std::vector<unsigned char> > solutions;
+
+ // TX_PUBKEY with incorrectly sized pubkey
+ s.clear();
+ s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_PUBKEYHASH with incorrectly sized key hash
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_SCRIPTHASH with incorrectly sized script hash
+ s.clear();
+ s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG 0/2
+ s.clear();
+ s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG 2/1
+ s.clear();
+ s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG n = 2 with 1 pubkey
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG n = 1 with 0 pubkeys
+ s.clear();
+ s << OP_1 << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_NULL_DATA with other opcodes
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_WITNESS with incorrect program size
+ s.clear();
+ s << OP_0 << std::vector<unsigned char>(19, 0x01);
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
+{
+ CKey key;
+ CPubKey pubkey;
+ key.MakeNewKey(true);
+ pubkey = key.GetPubKey();
+
+ CScript s;
+ CTxDestination address;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkey) << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CKeyID>(&address) &&
+ *boost::get<CKeyID>(&address) == pubkey.GetID());
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CKeyID>(&address) &&
+ *boost::get<CKeyID>(&address) == pubkey.GetID());
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CScriptID>(&address) &&
+ *boost::get<CScriptID>(&address) == CScriptID(redeemScript));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!ExtractDestination(s, address));
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75});
+ BOOST_CHECK(!ExtractDestination(s, address));
+
+ // TX_WITNESS_V0_KEYHASH
+ s.clear();
+ s << OP_0 << ToByteVector(pubkey.GetID());
+ BOOST_CHECK(ExtractDestination(s, address));
+ WitnessV0KeyHash keyhash;
+ CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
+ BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
+
+ // TX_WITNESS_V0_SCRIPTHASH
+ s.clear();
+ WitnessV0ScriptHash scripthash;
+ CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
+ s << OP_0 << ToByteVector(scripthash);
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
+
+ // TX_WITNESS with unknown version
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey);
+ BOOST_CHECK(ExtractDestination(s, address));
+ WitnessUnknown unk;
+ unk.length = 33;
+ unk.version = 1;
+ std::copy(pubkey.begin(), pubkey.end(), unk.program);
+ BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<CTxDestination> addresses;
+ int nRequired;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) &&
+ *boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(addresses.size(), 2);
+ BOOST_CHECK_EQUAL(nRequired, 2);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) &&
+ *boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID());
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75});
+ BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired));
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript expected, result;
+
+ // CKeyID
+ expected.clear();
+ expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ result = GetScriptForDestination(pubkeys[0].GetID());
+ BOOST_CHECK(result == expected);
+
+ // CScriptID
+ CScript redeemScript(result);
+ expected.clear();
+ expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ result = GetScriptForDestination(CScriptID(redeemScript));
+ BOOST_CHECK(result == expected);
+
+ // CNoDestination
+ expected.clear();
+ result = GetScriptForDestination(CNoDestination());
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForRawPubKey
+ expected.clear();
+ expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ result = GetScriptForRawPubKey(pubkeys[0]);
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForMultisig
+ expected.clear();
+ expected << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ ToByteVector(pubkeys[2]) <<
+ OP_3 << OP_CHECKMULTISIG;
+ result = GetScriptForMultisig(2, std::vector<CPubKey>(pubkeys, pubkeys + 3));
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForWitness
+ CScript witnessScript;
+
+ witnessScript << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ expected.clear();
+ expected << OP_0 << ToByteVector(pubkeys[0].GetID());
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+
+ witnessScript.clear();
+ witnessScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+
+ witnessScript.clear();
+ witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ expected.clear();
+ expected << OP_0 << ToByteVector(scriptHash);
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_IsMine)
+{
+ CKey keys[2];
+ CPubKey pubkeys[2];
+ for (int i = 0; i < 2; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CKey uncompressedKey;
+ uncompressedKey.MakeNewKey(false);
+ CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
+
+ CScript scriptPubKey;
+ isminetype result;
+ bool isInvalid;
+
+ // P2PK compressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PK uncompressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(uncompressedKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PKH compressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PKH uncompressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(uncompressedKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2SH
+ {
+ CBasicKeyStore keystore;
+
+ CScript redeemScript;
+ redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore does not have redeemScript or key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript but no key
+ keystore.AddCScript(redeemScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript and key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WPKH compressed
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID());
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key and P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WPKH uncompressed
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(uncompressedPubkey.GetID());
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key and P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(isInvalid);
+ }
+
+ // scriptPubKey multisig
+ {
+ CBasicKeyStore keystore;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ // Keystore does not have any keys
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has 1/2 keys
+ keystore.AddKey(uncompressedKey);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has 2/2 keys
+ keystore.AddKey(keys[1]);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2SH multisig
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+ keystore.AddKey(keys[1]);
+
+ CScript redeemScript;
+ redeemScript << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore has no redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript
+ keystore.AddCScript(redeemScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WSH multisig with compressed keys
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+ keystore.AddKey(keys[1]);
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(scriptHash);
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WSH multisig with uncompressed key
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+ keystore.AddKey(keys[1]);
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(scriptHash);
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(isInvalid);
+ }
+
+ // P2WSH multisig wrapped in P2SH
+ {
+ CBasicKeyStore keystore;
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ CScript redeemScript;
+ redeemScript << OP_0 << ToByteVector(scriptHash);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore has no witnessScript, P2SH redeemScript, or keys
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has witnessScript and P2SH redeemScript, but no keys
+ keystore.AddCScript(redeemScript);
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddKey(keys[0]);
+ keystore.AddKey(keys[1]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // OP_RETURN
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // Nonstandard
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 06b8274f2d..f96d867bc6 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -2,21 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "data/script_tests.json.h"
-
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
-#include "rpc/server.h"
+#include <test/data/script_tests.json.h>
+
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
+#include <rpc/server.h>
#if defined(HAVE_CONSENSUS_LIB)
-#include "script/bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
#endif
#include <fstream>
@@ -166,6 +166,17 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message);
+
+ // Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
+ for (int i = 0; i < 16; ++i) {
+ int extra_flags = InsecureRandBits(16);
+ int combined_flags = expect ? (flags & ~extra_flags) : (flags | extra_flags);
+ // Weed out some invalid flag combinations.
+ if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
+ if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
+ }
+
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
@@ -450,7 +461,7 @@ public:
return array;
}
- std::string GetComment()
+ std::string GetComment() const
{
return comment;
}
@@ -1451,4 +1462,21 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
BOOST_CHECK(!script.HasValidOps());
}
+BOOST_AUTO_TEST_CASE(script_can_append_self)
+{
+ CScript s, d;
+
+ s = ScriptFromHex("00");
+ s += s;
+ d = ScriptFromHex("0000");
+ BOOST_CHECK(s == d);
+
+ // check doubling a script that's large enough to require reallocation
+ static const char hex[] = "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f";
+ s = CScript() << ParseHex(hex) << OP_CHECKSIG;
+ d = CScript() << ParseHex(hex) << OP_CHECKSIG << ParseHex(hex) << OP_CHECKSIG;
+ s += s;
+ BOOST_CHECK(s == d);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index 94dd58526c..ad15427a9b 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -12,7 +12,7 @@
#include <stdint.h>
#include <string>
#include <vector>
-#include "assert.h"
+#include <assert.h>
class scriptnum10_error : public std::runtime_error
{
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 1d5893bdc3..aef500174a 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "scriptnum10.h"
-#include "script/script.h"
-#include "test/test_bitcoin.h"
+#include <test/scriptnum10.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <limits.h>
@@ -29,10 +29,7 @@ static void CheckCreateVch(const int64_t& num)
CScriptNum scriptnum(num);
BOOST_CHECK(verify(bignum, scriptnum));
- std::vector<unsigned char> vch = bignum.getvch();
-
CScriptNum10 bignum2(bignum.getvch(), false);
- vch = scriptnum.getvch();
CScriptNum scriptnum2(scriptnum.getvch(), false);
BOOST_CHECK(verify(bignum2, scriptnum2));
@@ -90,11 +87,10 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2)
const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
- bool invalid = false;
// int64_t overflow is undefined.
- invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
- (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
+ bool invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
+ (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
if (!invalid)
{
BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2));
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 9661a66514..28ed2bfeb0 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "serialize.h"
-#include "streams.h"
-#include "hash.h"
-#include "test/test_bitcoin.h"
+#include <serialize.h>
+#include <streams.h>
+#include <hash.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 1ca83a7cf8..d97e106287 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "data/sighash.json.h"
-#include "hash.h"
-#include "script/interpreter.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "streams.h"
-#include "test/test_bitcoin.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <test/data/sighash.json.h>
+#include <hash.h>
+#include <script/interpreter.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <streams.h>
+#include <test/test_bitcoin.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <iostream>
@@ -124,11 +124,9 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#if defined(PRINT_SIGHASH_JSON)
std::cout << "[\n";
std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
- #endif
+ int nRandomTests = 500;
+ #else
int nRandomTests = 50000;
-
- #if defined(PRINT_SIGHASH_JSON)
- nRandomTests = 500;
#endif
for (int i=0; i<nRandomTests; i++) {
int nHashType = InsecureRand32();
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index d3b8b07228..891cd1e1d8 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "pubkey.h"
-#include "key.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "uint256.h"
-#include "test/test_bitcoin.h"
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <pubkey.h>
+#include <key.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index e3654e67ad..1ffd9f2b42 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <chain.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <vector>
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(skiplist_test)
BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);
BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);
- BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]);
+ BOOST_CHECK(vIndex[from].GetAncestor(0) == vIndex.data());
}
}
@@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
for (unsigned int i=0; i<vBlocksSide.size(); i++) {
vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.
vBlocksSide[i].nHeight = i + 50000;
- vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999];
+ vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999);
vBlocksSide[i].phashBlock = &vHashSide[i];
vBlocksSide[i].BuildSkip();
BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight);
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index af2a152aa5..3636e6c332 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "streams.h"
-#include "support/allocators/zeroafterfree.h"
-#include "test/test_bitcoin.h"
+#include <streams.h>
+#include <support/allocators/zeroafterfree.h>
+#include <test/test_bitcoin.h>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/test/unit_test.hpp>
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 94ec7c03f5..f52c8ccc21 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -2,30 +2,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "test_bitcoin.h"
-
-#include "chainparams.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "crypto/sha256.h"
-#include "fs.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "net_processing.h"
-#include "pubkey.h"
-#include "random.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "rpc/server.h"
-#include "rpc/register.h"
-#include "script/sigcache.h"
-
-#include "test/testutil.h"
+#include <test/test_bitcoin.h>
+
+#include <chainparams.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <crypto/sha256.h>
+#include <validation.h>
+#include <miner.h>
+#include <net_processing.h>
+#include <ui_interface.h>
+#include <streams.h>
+#include <rpc/server.h>
+#include <rpc/register.h>
+#include <script/sigcache.h>
#include <memory>
+void CConnmanTest::AddNode(CNode& node)
+{
+ LOCK(g_connman->cs_vNodes);
+ g_connman->vNodes.push_back(&node);
+}
+
+void CConnmanTest::ClearNodes()
+{
+ LOCK(g_connman->cs_vNodes);
+ g_connman->vNodes.clear();
+}
+
uint256 insecure_rand_seed = GetRandHash();
FastRandomContext insecure_rand_ctx(insecure_rand_seed);
@@ -50,7 +55,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
- g_connman.reset();
}
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@@ -61,7 +65,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache();
- pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
+ pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
fs::create_directories(pathTemp);
gArgs.ForceSetArg("-datadir", pathTemp.string());
@@ -71,9 +75,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
mempool.setSanityCheck(1.0);
- pblocktree = new CBlockTreeDB(1 << 20, true);
- pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(pcoinsdbview);
+ pblocktree.reset(new CBlockTreeDB(1 << 20, true));
+ pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
+ pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}
@@ -88,25 +92,29 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
threadGroup.create_thread(&ThreadScriptCheck);
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
connman = g_connman.get();
- RegisterNodeSignals(GetNodeSignals());
+ peerLogic.reset(new PeerLogicValidation(connman, scheduler));
}
TestingSetup::~TestingSetup()
{
- UnregisterNodeSignals(GetNodeSignals());
threadGroup.interrupt_all();
threadGroup.join_all();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
+ g_connman.reset();
+ peerLogic.reset();
UnloadBlockIndex();
- delete pcoinsTip;
- delete pcoinsdbview;
- delete pblocktree;
+ pcoinsTip.reset();
+ pcoinsdbview.reset();
+ pblocktree.reset();
fs::remove_all(pathTemp);
}
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
+ // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
+ // TODO: fix the code to support SegWit blocks.
+ UpdateVersionBitsParameters(Consensus::DEPLOYMENT_SEGWIT, 0, Consensus::BIP9Deployment::NO_TIMEOUT);
// Generate a 100-block chain:
coinbaseKey.MakeNewKey(true);
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
@@ -135,7 +143,10 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
block.vtx.push_back(MakeTransactionRef(tx));
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
- IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+ {
+ LOCK(cs_main);
+ IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+ }
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
@@ -160,3 +171,15 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
spendsCoinbase, sigOpCost, lp);
}
+
+/**
+ * @returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
+ * with 9 txs.
+ */
+CBlock getBlock13b8a()
+{
+ CBlock block;
+ CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+ return block;
+}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index dd3b13c8c8..80a9cbaeea 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -5,14 +5,14 @@
#ifndef BITCOIN_TEST_TEST_BITCOIN_H
#define BITCOIN_TEST_TEST_BITCOIN_H
-#include "chainparamsbase.h"
-#include "fs.h"
-#include "key.h"
-#include "pubkey.h"
-#include "random.h"
-#include "scheduler.h"
-#include "txdb.h"
-#include "txmempool.h"
+#include <chainparamsbase.h>
+#include <fs.h>
+#include <key.h>
+#include <pubkey.h>
+#include <random.h>
+#include <scheduler.h>
+#include <txdb.h>
+#include <txmempool.h>
#include <boost/thread.hpp>
@@ -41,7 +41,7 @@ static inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); }
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
- BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -49,14 +49,21 @@ struct BasicTestingSetup {
* Included are data directory, coins database, script check threads setup.
*/
class CConnman;
+class CNode;
+struct CConnmanTest {
+ static void AddNode(CNode& node);
+ static void ClearNodes();
+};
+
+class PeerLogicValidation;
struct TestingSetup: public BasicTestingSetup {
- CCoinsViewDB *pcoinsdbview;
fs::path pathTemp;
boost::thread_group threadGroup;
CConnman* connman;
CScheduler scheduler;
+ std::unique_ptr<PeerLogicValidation> peerLogic;
- TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
};
@@ -97,7 +104,7 @@ struct TestMemPoolEntryHelper
TestMemPoolEntryHelper() :
nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
-
+
CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
CTxMemPoolEntry FromTx(const CTransaction &tx);
@@ -108,4 +115,7 @@ struct TestMemPoolEntryHelper
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
};
+
+CBlock getBlock13b8a();
+
#endif
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index de14251601..319d81187a 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -3,22 +3,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "consensus/merkle.h"
-#include "primitives/block.h"
-#include "script/script.h"
-#include "addrman.h"
-#include "chain.h"
-#include "coins.h"
-#include "compressor.h"
-#include "net.h"
-#include "protocol.h"
-#include "streams.h"
-#include "undo.h"
-#include "version.h"
-#include "pubkey.h"
+#include <consensus/merkle.h>
+#include <primitives/block.h>
+#include <script/script.h>
+#include <addrman.h>
+#include <chain.h>
+#include <coins.h>
+#include <compressor.h>
+#include <net.h>
+#include <protocol.h>
+#include <streams.h>
+#include <undo.h>
+#include <version.h>
+#include <pubkey.h>
+#include <blockencodings.h>
#include <stdint.h>
#include <unistd.h>
@@ -45,11 +46,13 @@ enum TEST_ID {
CBLOOMFILTER_DESERIALIZE,
CDISKBLOCKINDEX_DESERIALIZE,
CTXOUTCOMPRESSOR_DESERIALIZE,
+ BLOCKTRANSACTIONS_DESERIALIZE,
+ BLOCKTRANSACTIONSREQUEST_DESERIALIZE,
TEST_ID_END
};
-bool read_stdin(std::vector<char> &data) {
- char buffer[1024];
+bool read_stdin(std::vector<uint8_t> &data) {
+ uint8_t buffer[1024];
ssize_t length=0;
while((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
data.insert(data.end(), buffer, buffer+length);
@@ -59,15 +62,11 @@ bool read_stdin(std::vector<char> &data) {
return length==0;
}
-int do_fuzz()
-{
- std::vector<char> buffer;
- if (!read_stdin(buffer)) return 0;
-
+int test_one_input(std::vector<uint8_t> buffer) {
if (buffer.size() < sizeof(uint32_t)) return 0;
uint32_t test_id = 0xffffffff;
- memcpy(&test_id, &buffer[0], sizeof(uint32_t));
+ memcpy(&test_id, buffer.data(), sizeof(uint32_t));
buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));
if (test_id >= TEST_ID_END) return 0;
@@ -249,15 +248,58 @@ int do_fuzz()
break;
}
+ case BLOCKTRANSACTIONS_DESERIALIZE:
+ {
+ try
+ {
+ BlockTransactions bt;
+ ds >> bt;
+ } catch (const std::ios_base::failure& e) {return 0;}
+
+ break;
+ }
+ case BLOCKTRANSACTIONSREQUEST_DESERIALIZE:
+ {
+ try
+ {
+ BlockTransactionsRequest btr;
+ ds >> btr;
+ } catch (const std::ios_base::failure& e) {return 0;}
+
+ break;
+ }
default:
return 0;
}
return 0;
}
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
+void initialize() {
+ globalVerifyHandle = std::unique_ptr<ECCVerifyHandle>(new ECCVerifyHandle());
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ test_one_input(std::vector<uint8_t>(data, data + size));
+ return 0;
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ initialize();
+ return 0;
+}
+
+// Disabled under WIN32 due to clash with Cygwin's WinMain.
+#ifndef WIN32
+// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
+// the main(...) function.
+__attribute__((weak))
+#endif
int main(int argc, char **argv)
{
- ECCVerifyHandle globalVerifyHandle;
+ initialize();
#ifdef __AFL_INIT
// Enable AFL deferred forkserver mode. Requires compilation using
// afl-clang-fast++. See fuzzing.md for details.
@@ -267,11 +309,20 @@ int main(int argc, char **argv)
#ifdef __AFL_LOOP
// Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
// See fuzzing.md for details.
+ int ret = 0;
while (__AFL_LOOP(1000)) {
- do_fuzz();
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ continue;
+ }
+ ret = test_one_input(buffer);
}
- return 0;
+ return ret;
#else
- return do_fuzz();
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ return 0;
+ }
+ return test_one_input(buffer);
#endif
}
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
index 34beef5539..8d81ff6fc6 100644
--- a/src/test/test_bitcoin_main.cpp
+++ b/src/test/test_bitcoin_main.cpp
@@ -4,20 +4,20 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
-#include "net.h"
+#include <net.h>
#include <boost/test/unit_test.hpp>
std::unique_ptr<CConnman> g_connman;
-void Shutdown(void* parg)
+[[noreturn]] void Shutdown(void* parg)
{
- exit(EXIT_SUCCESS);
+ std::exit(EXIT_SUCCESS);
}
-void StartShutdown()
+[[noreturn]] void StartShutdown()
{
- exit(EXIT_SUCCESS);
+ std::exit(EXIT_SUCCESS);
}
bool ShutdownRequested()
diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp
deleted file mode 100644
index 591d0bf302..0000000000
--- a/src/test/testutil.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "testutil.h"
-
-#ifdef WIN32
-#include <shlobj.h>
-#endif
-
-#include "fs.h"
-
-fs::path GetTempPath() {
- return fs::temp_directory_path();
-}
diff --git a/src/test/testutil.h b/src/test/testutil.h
deleted file mode 100644
index cbe784d640..0000000000
--- a/src/test/testutil.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009-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.
-
-/**
- * Utility functions shared by unit tests
- */
-#ifndef BITCOIN_TEST_TESTUTIL_H
-#define BITCOIN_TEST_TESTUTIL_H
-
-#include "fs.h"
-
-fs::path GetTempPath();
-
-#endif // BITCOIN_TEST_TESTUTIL_H
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
index 34863fd9d0..9ff95bd2b0 100644
--- a/src/test/timedata_tests.cpp
+++ b/src/test/timedata_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include "timedata.h"
-#include "test/test_bitcoin.h"
+#include <timedata.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp
index b7affaacde..d0aa8659c2 100644
--- a/src/test/torcontrol_tests.cpp
+++ b/src/test/torcontrol_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include "test/test_bitcoin.h"
-#include "torcontrol.cpp"
+#include <test/test_bitcoin.h>
+#include <torcontrol.cpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 6654634bf1..34a182722d 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "data/tx_invalid.json.h"
-#include "data/tx_valid.json.h"
-#include "test/test_bitcoin.h"
-
-#include "clientversion.h"
-#include "checkqueue.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/sign.h"
-#include "script/script_error.h"
-#include "script/standard.h"
-#include "utilstrencodings.h"
+#include <test/data/tx_invalid.json.h>
+#include <test/data/tx_valid.json.h>
+#include <test/test_bitcoin.h>
+
+#include <clientversion.h>
+#include <checkqueue.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/sign.h>
+#include <script/script_error.h>
+#include <script/standard.h>
+#include <utilstrencodings.h>
#include <map>
#include <string>
@@ -480,8 +480,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
- const CTxOut& output = coins[tx.vin[i].prevout.n].out;
- CScriptCheck check(output.scriptPubKey, output.nValue, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
vChecks.push_back(CScriptCheck());
check.swap(vChecks.back());
control.Add(vChecks);
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
new file mode 100644
index 0000000000..2d1eb7b772
--- /dev/null
+++ b/src/test/txvalidation_tests.cpp
@@ -0,0 +1,61 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <validation.h>
+#include <txmempool.h>
+#include <amount.h>
+#include <consensus/validation.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_SUITE(txvalidation_tests)
+
+/**
+ * Ensure that the mempool won't accept coinbase transactions.
+ */
+BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
+{
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ CMutableTransaction coinbaseTx;
+
+ coinbaseTx.nVersion = 1;
+ coinbaseTx.vin.resize(1);
+ coinbaseTx.vout.resize(1);
+ coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL;
+ coinbaseTx.vout[0].nValue = 1 * CENT;
+ coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
+
+ assert(CTransaction(coinbaseTx).IsCoinBase());
+
+ CValidationState state;
+
+ LOCK(cs_main);
+
+ unsigned int initialPoolSize = mempool.size();
+
+ BOOST_CHECK_EQUAL(
+ false,
+ AcceptToMemoryPool(mempool, state, MakeTransactionRef(coinbaseTx),
+ nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */,
+ true /* bypass_limits */,
+ 0 /* nAbsurdFee */));
+
+ // Check that the transaction hasn't been added to mempool.
+ BOOST_CHECK_EQUAL(mempool.size(), initialPoolSize);
+
+ // Check that the validation state reflects the unsuccessful attempt.
+ BOOST_CHECK(state.IsInvalid());
+ BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
+
+ int nDoS;
+ BOOST_CHECK_EQUAL(state.IsInvalid(nDoS), true);
+ BOOST_CHECK_EQUAL(nDoS, 100);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 2d25cb96c8..fe8cb6126e 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -2,20 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/validation.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "pubkey.h"
-#include "txmempool.h"
-#include "random.h"
-#include "script/standard.h"
-#include "script/sign.h"
-#include "test/test_bitcoin.h"
-#include "utiltime.h"
-#include "core_io.h"
-#include "keystore.h"
-#include "policy/policy.h"
+#include <consensus/validation.h>
+#include <key.h>
+#include <validation.h>
+#include <miner.h>
+#include <pubkey.h>
+#include <txmempool.h>
+#include <random.h>
+#include <script/standard.h>
+#include <script/sign.h>
+#include <test/test_bitcoin.h>
+#include <utiltime.h>
+#include <core_io.h>
+#include <keystore.h>
+#include <policy/policy.h>
#include <boost/test/unit_test.hpp>
@@ -29,7 +29,8 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, nullptr, nullptr, true, 0);
+ return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
@@ -65,6 +66,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// Test 1: block with both of those transactions should be rejected.
block = CreateAndProcessBlock(spends, scriptPubKey);
+ LOCK(cs_main);
BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
// Test 2: ... and should be rejected if spend1 is in the memory pool
@@ -101,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// should fail.
// Capture this interaction with the upgraded_nop argument: set it when evaluating
// any script flag that is implemented as an upgraded NOP code.
-void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache, bool upgraded_nop)
+void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache)
{
PrecomputedTransactionData txdata(tx);
// If we add many more flags, this loop can get too expensive, but we can
@@ -118,29 +120,23 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
// WITNESS requires P2SH
test_flags |= SCRIPT_VERIFY_P2SH;
}
- bool ret = CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, nullptr);
+ bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr);
// CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags
bool expected_return_value = !(test_flags & failing_flags);
- if (expected_return_value && upgraded_nop) {
- // If the script flag being tested corresponds to an upgraded NOP,
- // then script execution should fail if DISCOURAGE_UPGRADABLE_NOPS
- // is set.
- expected_return_value = !(test_flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS);
- }
BOOST_CHECK_EQUAL(ret, expected_return_value);
// Test the caching
if (ret && add_to_cache) {
// Check that we get a cache hit if the tx was valid
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK(scriptchecks.empty());
} else {
// Check that we get script executions to check, if the transaction
// was invalid, or we didn't add to cache.
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
}
}
@@ -150,7 +146,10 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
{
// Test that passing CheckInputs with one set of script flags doesn't imply
// that we would pass again with a different set of flags.
- InitScriptExecutionCache();
+ {
+ LOCK(cs_main);
+ InitScriptExecutionCache();
+ }
CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey));
@@ -200,20 +199,20 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx);
- BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
+ BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
// If we call again asking for scriptchecks (as happens in
// ConnectBlock), we should add a script check object for this -- we're
// not caching invalidity (if that changes, delete this test case).
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
+ BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), 1);
// Test that CheckInputs returns true iff DERSIG-enforcing flags are
// not present. Don't add these checks to the cache, so that we can
// test later that block validation works fine in the absence of cached
// successes.
- ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, false);
+ ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false);
// And if we produce a block with this tx, it should be valid (DERSIG not
// enabled yet), even though there's no cache entry.
@@ -238,7 +237,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
- ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true, false);
+ ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true);
}
// Test CHECKLOCKTIMEVERIFY
@@ -261,13 +260,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
- ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true);
+ ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true);
// Make it valid, and check again
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
- BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
}
// TEST CHECKSEQUENCEVERIFY
@@ -289,13 +288,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
vchSig.push_back((unsigned char)SIGHASH_ALL);
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
- ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true);
+ ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true);
// Make it valid, and check again
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_csv_tx);
- BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
}
// TODO: add tests for remaining script flags
@@ -318,11 +317,11 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
UpdateTransaction(valid_with_witness_tx, 0, sigdata);
// This should be valid under all script flags.
- ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true, false);
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true);
// Remove the witness, and check that it is now invalid.
valid_with_witness_tx.vin[0].scriptWitness.SetNull();
- ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true, false);
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true);
}
{
@@ -347,7 +346,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
}
// This should be valid under all script flags
- ValidateCheckInputsForAllFlags(tx, 0, true, false);
+ ValidateCheckInputsForAllFlags(tx, 0, true);
// Check that if the second input is invalid, but the first input is
// valid, the transaction is not cached.
@@ -357,12 +356,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData txdata(tx);
// This transaction is now invalid under segwit, because of the second input.
- BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
+ BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
std::vector<CScriptCheck> scriptchecks;
// Make sure this transaction was not cached (ie because the first
// input was valid)
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
// Should get 2 script checks back -- caching is on a whole-transaction basis.
BOOST_CHECK_EQUAL(scriptchecks.size(), 2);
}
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index 70d83a2e54..40ef9adb2e 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,10 +1,10 @@
// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "arith_uint256.h"
-#include "uint256.h"
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <arith_uint256.h>
+#include <uint256.h>
+#include <version.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <stdint.h>
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index dffe8e55a8..7386204437 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -8,7 +8,7 @@
#include <string>
#include <map>
#include <univalue.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 5679086969..998090cd9b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
+#include <util.h>
-#include "clientversion.h"
-#include "primitives/transaction.h"
-#include "sync.h"
-#include "utilstrencodings.h"
-#include "utilmoneystr.h"
-#include "test/test_bitcoin.h"
+#include <clientversion.h>
+#include <primitives/transaction.h>
+#include <sync.h>
+#include <utilstrencodings.h>
+#include <utilmoneystr.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
#include <vector>
@@ -253,6 +253,31 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+BOOST_AUTO_TEST_CASE(util_IsHexNumber)
+{
+ BOOST_CHECK(IsHexNumber("0x0"));
+ BOOST_CHECK(IsHexNumber("0"));
+ BOOST_CHECK(IsHexNumber("0x10"));
+ BOOST_CHECK(IsHexNumber("10"));
+ BOOST_CHECK(IsHexNumber("0xff"));
+ BOOST_CHECK(IsHexNumber("ff"));
+ BOOST_CHECK(IsHexNumber("0xFfa"));
+ BOOST_CHECK(IsHexNumber("Ffa"));
+ BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+ BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+
+ BOOST_CHECK(!IsHexNumber("")); // empty string not allowed
+ BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed
+ BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end,
+ BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning,
+ BOOST_CHECK(!IsHexNumber("0x 0")); // or middle,
+ BOOST_CHECK(!IsHexNumber(" ")); // etc.
+ BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character
+ BOOST_CHECK(!IsHexNumber("x0")); // broken prefix
+ BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed
+
+}
+
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
SeedInsecureRand(true);
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index f433aad889..7029b347dd 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "versionbits.h"
-#include "test/test_bitcoin.h"
-#include "chainparams.h"
-#include "validation.h"
-#include "consensus/params.h"
+#include <chain.h>
+#include <versionbits.h>
+#include <test/test_bitcoin.h>
+#include <chainparams.h>
+#include <validation.h>
+#include <consensus/params.h>
#include <boost/test/unit_test.hpp>
@@ -32,6 +32,12 @@ public:
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
};
+class TestAlwaysActiveConditionChecker : public TestConditionChecker
+{
+public:
+ int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::ALWAYS_ACTIVE; }
+};
+
#define CHECKERS 6
class VersionBitsTester
@@ -43,6 +49,8 @@ class VersionBitsTester
// The first one performs all checks, the second only 50%, the third only 25%, etc...
// This is to test whether lack of cached information leads to the same results.
TestConditionChecker checker[CHECKERS];
+ // Another 6 that assume always active activation
+ TestAlwaysActiveConditionChecker checker_always[CHECKERS];
// Test counter (to identify failures)
int num;
@@ -56,6 +64,7 @@ public:
}
for (unsigned int i = 0; i < CHECKERS; i++) {
checker[i] = TestConditionChecker();
+ checker_always[i] = TestAlwaysActiveConditionChecker();
}
vpblock.clear();
return *this;
@@ -82,6 +91,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));
}
}
num++;
@@ -92,6 +102,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -102,6 +113,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -112,6 +124,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -122,6 +135,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -132,6 +146,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -314,20 +329,20 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
- lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Mine another period worth of blocks, signaling the new bit.
- lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ lastBlock = secondChain.Mine(4032, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
- lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6047, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
- lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp
index 9d691079ed..7bcacc3014 100644
--- a/src/threadinterrupt.cpp
+++ b/src/threadinterrupt.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "threadinterrupt.h"
+#include <threadinterrupt.h>
CThreadInterrupt::operator bool() const
{
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 5113bb60db..b91cf01723 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -3,17 +3,17 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "timedata.h"
+#include <timedata.h>
-#include "netaddress.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "warnings.h"
+#include <netaddress.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <warnings.h>
static CCriticalSection cs_nTimeOffset;
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 5022d46809..d34cfaa94f 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -167,7 +167,7 @@ namespace tinyformat {
class format_error: public std::runtime_error
{
public:
- format_error(const std::string &what): std::runtime_error(what) {
+ explicit format_error(const std::string &what): std::runtime_error(what) {
}
};
@@ -495,10 +495,14 @@ namespace detail {
class FormatArg
{
public:
- FormatArg() {}
+ FormatArg()
+ : m_value(nullptr),
+ m_formatImpl(nullptr),
+ m_toIntImpl(nullptr)
+ { }
template<typename T>
- FormatArg(const T& value)
+ explicit FormatArg(const T& value)
: m_value(static_cast<const void*>(&value)),
m_formatImpl(&formatImpl<T>),
m_toIntImpl(&toIntImpl<T>)
@@ -507,11 +511,15 @@ class FormatArg
void format(std::ostream& out, const char* fmtBegin,
const char* fmtEnd, int ntrunc) const
{
+ assert(m_value);
+ assert(m_formatImpl);
m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
}
int toInt() const
{
+ assert(m_value);
+ assert(m_toIntImpl);
return m_toIntImpl(m_value);
}
@@ -712,23 +720,27 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
break;
case 'X':
out.setf(std::ios::uppercase);
+ // Falls through
case 'x': case 'p':
out.setf(std::ios::hex, std::ios::basefield);
intConversion = true;
break;
case 'E':
out.setf(std::ios::uppercase);
+ // Falls through
case 'e':
out.setf(std::ios::scientific, std::ios::floatfield);
out.setf(std::ios::dec, std::ios::basefield);
break;
case 'F':
out.setf(std::ios::uppercase);
+ // Falls through
case 'f':
out.setf(std::ios::fixed, std::ios::floatfield);
break;
case 'G':
out.setf(std::ios::uppercase);
+ // Falls through
case 'g':
out.setf(std::ios::dec, std::ios::basefield);
// As in boost::format, let stream decide float format.
@@ -867,7 +879,7 @@ class FormatListN : public FormatList
public:
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
template<typename... Args>
- FormatListN(const Args&... args)
+ explicit FormatListN(const Args&... args)
: FormatList(&m_formatterStore[0], N),
m_formatterStore { FormatArg(args)... }
{ static_assert(sizeof...(args) == N, "Number of args must be N"); }
@@ -876,7 +888,7 @@ class FormatListN : public FormatList
# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
\
template<TINYFORMAT_ARGTYPES(n)> \
- FormatListN(TINYFORMAT_VARARGS(n)) \
+ explicit FormatListN(TINYFORMAT_VARARGS(n)) \
: FormatList(&m_formatterStore[0], n) \
{ assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
\
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index e8bc3e5e75..46f39d65a0 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "torcontrol.h"
-#include "utilstrencodings.h"
-#include "netbase.h"
-#include "net.h"
-#include "util.h"
-#include "crypto/hmac_sha256.h"
+#include <torcontrol.h>
+#include <utilstrencodings.h>
+#include <netbase.h>
+#include <net.h>
+#include <util.h>
+#include <crypto/hmac_sha256.h>
#include <vector>
#include <deque>
@@ -76,7 +76,7 @@ public:
/** Create a new TorControlConnection.
*/
- TorControlConnection(struct event_base *base);
+ explicit TorControlConnection(struct event_base *base);
~TorControlConnection();
/**
@@ -121,7 +121,7 @@ private:
};
TorControlConnection::TorControlConnection(struct event_base *_base):
- base(_base), b_conn(0)
+ base(_base), b_conn(nullptr)
{
}
@@ -227,7 +227,7 @@ bool TorControlConnection::Disconnect()
{
if (b_conn)
bufferevent_free(b_conn);
- b_conn = 0;
+ b_conn = nullptr;
return true;
}
@@ -476,7 +476,7 @@ TorController::~TorController()
{
if (reconnect_ev) {
event_free(reconnect_ev);
- reconnect_ev = 0;
+ reconnect_ev = nullptr;
}
if (service.IsValid()) {
RemoveLocal(service);
@@ -770,7 +770,7 @@ void StopTorControl()
if (gBase) {
torControlThread.join();
event_base_free(gBase);
- gBase = 0;
+ gBase = nullptr;
}
}
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 72dc82c5b1..a01eeefeb8 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -8,7 +8,7 @@
#ifndef BITCOIN_TORCONTROL_H
#define BITCOIN_TORCONTROL_H
-#include "scheduler.h"
+#include <scheduler.h>
extern const std::string DEFAULT_TOR_CONTROL;
static const bool DEFAULT_LISTEN_ONION = true;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 4c1b04cd94..7a8e854b55 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "txdb.h"
+#include <txdb.h>
-#include "chainparams.h"
-#include "hash.h"
-#include "random.h"
-#include "pow.h"
-#include "uint256.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "init.h"
+#include <chainparams.h>
+#include <hash.h>
+#include <random.h>
+#include <pow.h>
+#include <uint256.h>
+#include <util.h>
+#include <ui_interface.h>
+#include <init.h>
#include <stdint.h>
@@ -35,7 +35,7 @@ namespace {
struct CoinEntry {
COutPoint* outpoint;
char key;
- CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
+ explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
template<typename Stream>
void Serialize(Stream &s) const {
@@ -371,9 +371,9 @@ bool CCoinsViewDB::Upgrade() {
int64_t count = 0;
LogPrintf("Upgrading utxo-set database...\n");
LogPrintf("[0%%]...");
+ uiInterface.ShowProgress(_("Upgrading UTXO database"), 0, true);
size_t batch_size = 1 << 24;
CDBBatch batch(db);
- uiInterface.SetProgressBreakAction(StartShutdown);
int reportDone = 0;
std::pair<unsigned char, uint256> key;
std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()};
@@ -386,7 +386,7 @@ bool CCoinsViewDB::Upgrade() {
if (count++ % 256 == 0) {
uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1);
int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
- uiInterface.ShowProgress(_("Upgrading UTXO database") + "\n"+ _("(press q to shutdown and continue later)") + "\n", percentageDone);
+ uiInterface.ShowProgress(_("Upgrading UTXO database"), percentageDone, true);
if (reportDone < percentageDone/10) {
// report max. every 10% step
LogPrintf("[%d%%]...", percentageDone);
@@ -420,7 +420,7 @@ bool CCoinsViewDB::Upgrade() {
}
db.WriteBatch(batch);
db.CompactRange({DB_COINS, uint256()}, key);
- uiInterface.SetProgressBreakAction(std::function<void(void)>());
+ uiInterface.ShowProgress("", 100, false);
LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
return !ShutdownRequested();
}
diff --git a/src/txdb.h b/src/txdb.h
index adcbc73380..2e8095e3cd 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_TXDB_H
#define BITCOIN_TXDB_H
-#include "coins.h"
-#include "dbwrapper.h"
-#include "chain.h"
+#include <coins.h>
+#include <dbwrapper.h>
+#include <chain.h>
#include <map>
#include <string>
@@ -64,12 +64,12 @@ struct CDiskTxPos : public CDiskBlockPos
};
/** CCoinsView backed by the coin database (chainstate/) */
-class CCoinsViewDB : public CCoinsView
+class CCoinsViewDB final : public CCoinsView
{
protected:
CDBWrapper db;
public:
- CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+ explicit CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
@@ -109,18 +109,18 @@ private:
class CBlockTreeDB : public CDBWrapper
{
public:
- CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
-private:
- CBlockTreeDB(const CBlockTreeDB&);
- void operator=(const CBlockTreeDB&);
-public:
+ explicit CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+
+ CBlockTreeDB(const CBlockTreeDB&) = delete;
+ CBlockTreeDB& operator=(const CBlockTreeDB&) = delete;
+
bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo);
- bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
+ bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info);
bool ReadLastBlockFile(int &nFile);
- bool WriteReindexing(bool fReindex);
- bool ReadReindexing(bool &fReindex);
+ bool WriteReindexing(bool fReindexing);
+ bool ReadReindexing(bool &fReindexing);
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
- bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
+ bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &vect);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 4a81055231..392323808f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -3,20 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "txmempool.h"
-
-#include "consensus/consensus.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "policy/fees.h"
-#include "reverse_iterator.h"
-#include "streams.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utiltime.h"
+#include <txmempool.h>
+
+#include <consensus/consensus.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <policy/fees.h>
+#include <reverse_iterator.h>
+#include <streams.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utiltime.h>
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
@@ -39,11 +39,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
nSigOpCostWithAncestors = sigOpCost;
}
-CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
-{
- *this = other;
-}
-
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
@@ -322,7 +317,7 @@ void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFe
assert(int64_t(nCountWithDescendants) > 0);
}
-void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps)
+void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
{
nSizeWithAncestors += modifySize;
assert(int64_t(nSizeWithAncestors) > 0);
@@ -612,6 +607,15 @@ void CTxMemPool::clear()
_clear();
}
+static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
+{
+ CValidationState state;
+ CAmount txfee = 0;
+ bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee);
+ assert(fCheckResult);
+ UpdateCoins(tx, mempoolDuplicate, 1000000);
+}
+
void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{
if (nCheckFrequency == 0)
@@ -626,7 +630,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
uint64_t innerUsage = 0;
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
- const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate);
+ const int64_t spendheight = GetSpendHeight(mempoolDuplicate);
LOCK(cs);
std::list<const CTxMemPoolEntry*> waitingOnDependants;
@@ -705,11 +709,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
else {
- CValidationState state;
- bool fCheckResult = tx.IsCoinBase() ||
- Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight);
- assert(fCheckResult);
- UpdateCoins(tx, mempoolDuplicate, 1000000);
+ CheckInputsAndUpdateCoins(tx, mempoolDuplicate, spendheight);
}
}
unsigned int stepsSinceLastRemove = 0;
@@ -722,10 +722,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
stepsSinceLastRemove++;
assert(stepsSinceLastRemove < waitingOnDependants.size());
} else {
- bool fCheckResult = entry->GetTx().IsCoinBase() ||
- Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight);
- assert(fCheckResult);
- UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
+ CheckInputsAndUpdateCoins(entry->GetTx(), mempoolDuplicate, spendheight);
stepsSinceLastRemove = 0;
}
}
@@ -986,7 +983,7 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons
CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
LOCK(cs);
if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
- return CFeeRate(rollingMinimumFeeRate);
+ return CFeeRate(llround(rollingMinimumFeeRate));
int64_t time = GetTime();
if (time > lastRollingFeeUpdate + 10) {
@@ -1004,7 +1001,7 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
return CFeeRate(0);
}
}
- return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);
+ return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
}
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
diff --git a/src/txmempool.h b/src/txmempool.h
index 6723ea8e6c..86a008d7b2 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -13,19 +13,18 @@
#include <utility>
#include <string>
-#include "amount.h"
-#include "coins.h"
-#include "indirectmap.h"
-#include "policy/feerate.h"
-#include "primitives/transaction.h"
-#include "sync.h"
-#include "random.h"
-
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
-#include "boost/multi_index/hashed_index.hpp"
+#include <amount.h>
+#include <coins.h>
+#include <indirectmap.h>
+#include <policy/feerate.h>
+#include <primitives/transaction.h>
+#include <sync.h>
+#include <random.h>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
-
#include <boost/signals2/signal.hpp>
class CBlockIndex;
@@ -95,8 +94,6 @@ public:
bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp);
- CTxMemPoolEntry(const CTxMemPoolEntry& other);
-
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
@@ -112,7 +109,7 @@ public:
// Adjusts the descendant state.
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
// Adjusts the ancestor state
- void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);
+ void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
@@ -167,7 +164,7 @@ struct update_ancestor_state
struct update_fee_delta
{
- update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
+ explicit update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }
@@ -177,7 +174,7 @@ private:
struct update_lock_points
{
- update_lock_points(const LockPoints& _lp) : lp(_lp) { }
+ explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
@@ -207,7 +204,7 @@ struct mempoolentry_txid
class CompareTxMemPoolEntryByDescendantScore
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
bool fUseADescendants = UseDescendantScore(a);
bool fUseBDescendants = UseDescendantScore(b);
@@ -229,7 +226,7 @@ public:
}
// Calculate which score to use for an entry (avoiding division).
- bool UseDescendantScore(const CTxMemPoolEntry &a)
+ bool UseDescendantScore(const CTxMemPoolEntry &a) const
{
double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
@@ -244,7 +241,7 @@ public:
class CompareTxMemPoolEntryByScore
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
double f1 = (double)a.GetModifiedFee() * b.GetTxSize();
double f2 = (double)b.GetModifiedFee() * a.GetTxSize();
@@ -258,7 +255,7 @@ public:
class CompareTxMemPoolEntryByEntryTime
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
return a.GetTime() < b.GetTime();
}
@@ -267,7 +264,7 @@ public:
class CompareTxMemPoolEntryByAncestorFee
{
public:
- bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
double aFees = a.GetModFeesWithAncestors();
double aSize = a.GetSizeWithAncestors();
@@ -501,7 +498,7 @@ public:
/** Create a new CTxMemPool.
*/
- CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
+ explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
/**
* If sanity-checking is turned on, check makes sure the pool is
@@ -510,12 +507,15 @@ public:
* check does nothing.
*/
void check(const CCoinsViewCache *pcoins) const;
- void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }
+ void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
// addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
// then invoke the second version.
+ // Note that addUnchecked is ONLY called from ATMP outside of tests
+ // and any other callers may break wallet's in-mempool tracking (due to
+ // lack of CValidationInterface::TransactionAddedToMempool callbacks).
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);
@@ -606,7 +606,7 @@ public:
return mapTx.size();
}
- uint64_t GetTotalTxSize()
+ uint64_t GetTotalTxSize() const
{
LOCK(cs);
return totalTxSize;
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index 74a13e0e05..c0f7defa46 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "ui_interface.h"
-#include "util.h"
+#include <ui_interface.h>
+#include <util.h>
CClientUIInterface uiInterface;
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 762dd19b19..7f68c578ee 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -94,11 +94,11 @@ public:
/** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet;
- /** Show progress e.g. for verifychain */
- boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
-
- /** Set progress break action (possible "cancel button" triggers that action) */
- boost::signals2::signal<void (std::function<void(void)> action)> SetProgressBreakAction;
+ /**
+ * Show progress e.g. for verifychain.
+ * resume_possible indicates shutting down now will result in the current progress action resuming upon restart.
+ */
+ boost::signals2::signal<void (const std::string &title, int nProgress, bool resume_possible)> ShowProgress;
/** New block has been accepted */
boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;
diff --git a/src/uint256.cpp b/src/uint256.cpp
index c4c7b716fe..b7255231c1 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "uint256.h"
+#include <uint256.h>
-#include "utilstrencodings.h"
+#include <utilstrencodings.h>
#include <stdio.h>
#include <string.h>
@@ -14,7 +14,7 @@ template <unsigned int BITS>
base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
{
assert(vch.size() == sizeof(data));
- memcpy(data, &vch[0], sizeof(data));
+ memcpy(data, vch.data(), sizeof(data));
}
template <unsigned int BITS>
diff --git a/src/uint256.h b/src/uint256.h
index a92ce07f11..e45c990dae 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -12,14 +12,14 @@
#include <stdint.h>
#include <string>
#include <vector>
-#include "crypto/common.h"
+#include <crypto/common.h>
/** Template base class for fixed-sized opaque blobs. */
template<unsigned int BITS>
class base_blob
{
protected:
- enum { WIDTH=BITS/8 };
+ static constexpr int WIDTH = BITS / 8;
uint8_t data[WIDTH];
public:
base_blob()
@@ -111,7 +111,6 @@ public:
class uint160 : public base_blob<160> {
public:
uint160() {}
- uint160(const base_blob<160>& b) : base_blob<160>(b) {}
explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
};
@@ -123,7 +122,6 @@ public:
class uint256 : public base_blob<256> {
public:
uint256() {}
- uint256(const base_blob<256>& b) : base_blob<256>(b) {}
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
/** A cheap hash function that just returns 64 bits from the result, it can be
diff --git a/src/undo.h b/src/undo.h
index 0f9d041bbd..b482fd3089 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_UNDO_H
#define BITCOIN_UNDO_H
-#include "compressor.h"
-#include "consensus/consensus.h"
-#include "primitives/transaction.h"
-#include "serialize.h"
+#include <compressor.h>
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <serialize.h>
/** Undo information for a CTxIn
*
@@ -33,7 +33,7 @@ public:
::Serialize(s, CTxOutCompressor(REF(txout->out)));
}
- TxInUndoSerializer(const Coin* coin) : txout(coin) {}
+ explicit TxInUndoSerializer(const Coin* coin) : txout(coin) {}
};
class TxInUndoDeserializer
@@ -57,7 +57,7 @@ public:
::Unserialize(s, REF(CTxOutCompressor(REF(txout->out))));
}
- TxInUndoDeserializer(Coin* coin) : txout(coin) {}
+ explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {}
};
static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am
index 6c1ec81e63..e283fc890e 100644
--- a/src/univalue/Makefile.am
+++ b/src/univalue/Makefile.am
@@ -12,6 +12,7 @@ pkgconfig_DATA = pc/libunivalue.pc
libunivalue_la_SOURCES = \
lib/univalue.cpp \
+ lib/univalue_get.cpp \
lib/univalue_read.cpp \
lib/univalue_write.cpp
@@ -20,7 +21,7 @@ libunivalue_la_LDFLAGS = \
-no-undefined
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
-TESTS = test/unitester
+TESTS = test/object test/unitester test/no_nul
GENBIN = gen/gen$(BUILD_EXEEXT)
GEN_SRCS = gen/gen.cpp
@@ -33,7 +34,7 @@ gen: lib/univalue_escapes.h $(GENBIN)
@echo Updating $<
$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h
-noinst_PROGRAMS = $(TESTS)
+noinst_PROGRAMS = $(TESTS) test/test_json
TEST_DATA_DIR=test
@@ -42,6 +43,21 @@ test_unitester_LDADD = libunivalue.la
test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\"
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+test_test_json_SOURCES = test/test_json.cpp
+test_test_json_LDADD = libunivalue.la
+test_test_json_CXXFLAGS = -I$(top_srcdir)/include
+test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+
+test_no_nul_SOURCES = test/no_nul.cpp
+test_no_nul_LDADD = libunivalue.la
+test_no_nul_CXXFLAGS = -I$(top_srcdir)/include
+test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+
+test_object_SOURCES = test/object.cpp
+test_object_LDADD = libunivalue.la
+test_object_CXXFLAGS = -I$(top_srcdir)/include
+test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
+
TEST_FILES = \
$(TEST_DATA_DIR)/fail10.json \
$(TEST_DATA_DIR)/fail11.json \
@@ -77,6 +93,8 @@ TEST_FILES = \
$(TEST_DATA_DIR)/fail39.json \
$(TEST_DATA_DIR)/fail40.json \
$(TEST_DATA_DIR)/fail41.json \
+ $(TEST_DATA_DIR)/fail42.json \
+ $(TEST_DATA_DIR)/fail44.json \
$(TEST_DATA_DIR)/fail3.json \
$(TEST_DATA_DIR)/fail4.json \
$(TEST_DATA_DIR)/fail5.json \
@@ -88,6 +106,11 @@ TEST_FILES = \
$(TEST_DATA_DIR)/pass2.json \
$(TEST_DATA_DIR)/pass3.json \
$(TEST_DATA_DIR)/round1.json \
- $(TEST_DATA_DIR)/round2.json
+ $(TEST_DATA_DIR)/round2.json \
+ $(TEST_DATA_DIR)/round3.json \
+ $(TEST_DATA_DIR)/round4.json \
+ $(TEST_DATA_DIR)/round5.json \
+ $(TEST_DATA_DIR)/round6.json \
+ $(TEST_DATA_DIR)/round7.json
EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS)
diff --git a/src/univalue/README b/src/univalue/README
deleted file mode 100644
index 48167b083b..0000000000
--- a/src/univalue/README
+++ /dev/null
@@ -1,7 +0,0 @@
-
- UniValue
-
-A universal value object, with JSON encoding (output) and decoding (input).
-
-Built as a single dynamic RAII C++ object class, and no templates.
-
diff --git a/src/univalue/README.md b/src/univalue/README.md
new file mode 100644
index 0000000000..36aa786a4c
--- /dev/null
+++ b/src/univalue/README.md
@@ -0,0 +1,32 @@
+
+# UniValue
+
+## Summary
+
+A universal value class, with JSON encoding and decoding.
+
+UniValue is an abstract data type that may be a null, boolean, string,
+number, array container, or a key/value dictionary container, nested to
+an arbitrary depth.
+
+This class is aligned with the JSON standard, [RFC
+7159](https://tools.ietf.org/html/rfc7159.html).
+
+## Installation
+
+This project is a standard GNU
+[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html)
+project. Build and install instructions are available in the `INSTALL`
+file provided with GNU autotools.
+
+```
+$ ./autogen.sh
+$ ./configure
+$ make
+```
+
+## Design
+
+UniValue provides a single dynamic RAII C++ object class,
+and minimizes template use (contra json_spirit).
+
diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac
index 93d3ba945d..8298332ac1 100644
--- a/src/univalue/configure.ac
+++ b/src/univalue/configure.ac
@@ -1,7 +1,7 @@
m4_define([libunivalue_major_version], [1])
m4_define([libunivalue_minor_version], [1])
-m4_define([libunivalue_micro_version], [2])
-m4_define([libunivalue_interface_age], [2])
+m4_define([libunivalue_micro_version], [3])
+m4_define([libunivalue_interface_age], [3])
# If you need a modifier for the version number.
# Normally empty, but can be used to make "fixup" releases.
m4_define([libunivalue_extraversion], [])
@@ -14,7 +14,7 @@ m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_inter
m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])
-AC_INIT([univalue], [1.0.2],
+AC_INIT([univalue], [1.0.3],
[http://github.com/jgarzik/univalue/])
dnl make the compilation flags quiet unless V=1 is used
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index e8ce283519..4fd2223b30 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -7,6 +7,7 @@
#define __UNIVALUE_H__
#include <stdint.h>
+#include <string.h>
#include <string>
#include <vector>
@@ -69,10 +70,11 @@ public:
size_t size() const { return values.size(); }
bool getBool() const { return isTrue(); }
- bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
+ void getObjMap(std::map<std::string,UniValue>& kv) const;
+ bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
const UniValue& operator[](const std::string& key) const;
- const UniValue& operator[](unsigned int index) const;
- bool exists(const std::string& key) const { return (findKey(key) >= 0); }
+ const UniValue& operator[](size_t index) const;
+ bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
bool isNull() const { return (typ == VNULL); }
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
@@ -92,8 +94,25 @@ public:
std::string s(val_);
return push_back(s);
}
+ bool push_back(uint64_t val_) {
+ UniValue tmpVal(val_);
+ return push_back(tmpVal);
+ }
+ bool push_back(int64_t val_) {
+ UniValue tmpVal(val_);
+ return push_back(tmpVal);
+ }
+ bool push_back(int val_) {
+ UniValue tmpVal(val_);
+ return push_back(tmpVal);
+ }
+ bool push_back(double val_) {
+ UniValue tmpVal(val_);
+ return push_back(tmpVal);
+ }
bool push_backV(const std::vector<UniValue>& vec);
+ void __pushKV(const std::string& key, const UniValue& val);
bool pushKV(const std::string& key, const UniValue& val);
bool pushKV(const std::string& key, const std::string& val_) {
UniValue tmpVal(VSTR, val_);
@@ -124,9 +143,10 @@ public:
std::string write(unsigned int prettyIndent = 0,
unsigned int indentLevel = 0) const;
- bool read(const char *raw);
+ bool read(const char *raw, size_t len);
+ bool read(const char *raw) { return read(raw, strlen(raw)); }
bool read(const std::string& rawStr) {
- return read(rawStr.c_str());
+ return read(rawStr.data(), rawStr.size());
}
private:
@@ -135,7 +155,7 @@ private:
std::vector<std::string> keys;
std::vector<UniValue> values;
- int findKey(const std::string& key) const;
+ bool findKey(const std::string& key, size_t& retIdx) const;
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
@@ -240,7 +260,7 @@ enum jtokentype {
};
extern enum jtokentype getJsonToken(std::string& tokenVal,
- unsigned int& consumed, const char *raw);
+ unsigned int& consumed, const char *raw, const char *end);
extern const char *uvTypeName(UniValue::VType t);
static inline bool jsonTokenIsValue(enum jtokentype jtt)
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 5a2860c13f..d8ad7c4b90 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -4,75 +4,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <stdint.h>
-#include <errno.h>
#include <iomanip>
-#include <limits>
#include <sstream>
-#include <stdexcept>
#include <stdlib.h>
-#include <string.h>
#include "univalue.h"
-namespace
-{
-static bool ParsePrechecks(const std::string& str)
-{
- if (str.empty()) // No empty string allowed
- return false;
- if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
- return false;
- if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
- return false;
- return true;
-}
-
-bool ParseInt32(const std::string& str, int32_t *out)
-{
- if (!ParsePrechecks(str))
- return false;
- char *endp = NULL;
- errno = 0; // strtol will not set errno if valid
- long int n = strtol(str.c_str(), &endp, 10);
- if(out) *out = (int32_t)n;
- // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
- // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
- // platforms the size of these types may be different.
- return endp && *endp == 0 && !errno &&
- n >= std::numeric_limits<int32_t>::min() &&
- n <= std::numeric_limits<int32_t>::max();
-}
-
-bool ParseInt64(const std::string& str, int64_t *out)
-{
- if (!ParsePrechecks(str))
- return false;
- char *endp = NULL;
- errno = 0; // strtoll will not set errno if valid
- long long int n = strtoll(str.c_str(), &endp, 10);
- if(out) *out = (int64_t)n;
- // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
- // we still have to check that the returned value is within the range of an *int64_t*.
- return endp && *endp == 0 && !errno &&
- n >= std::numeric_limits<int64_t>::min() &&
- n <= std::numeric_limits<int64_t>::max();
-}
-
-bool ParseDouble(const std::string& str, double *out)
-{
- if (!ParsePrechecks(str))
- return false;
- if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
- return false;
- std::istringstream text(str);
- text.imbue(std::locale::classic());
- double result;
- text >> result;
- if(out) *out = result;
- return text.eof() && !text.fail();
-}
-}
-
using namespace std;
const UniValue NullUniValue;
@@ -104,7 +41,7 @@ static bool validNumStr(const string& s)
{
string tokenVal;
unsigned int consumed;
- enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
+ enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
return (tt == JTOK_NUMBER);
}
@@ -189,13 +126,22 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
return true;
}
+void UniValue::__pushKV(const std::string& key, const UniValue& val_)
+{
+ keys.push_back(key);
+ values.push_back(val_);
+}
+
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
{
if (typ != VOBJ)
return false;
- keys.push_back(key);
- values.push_back(val_);
+ size_t idx;
+ if (findKey(key, idx))
+ values[idx] = val_;
+ else
+ __pushKV(key, val_);
return true;
}
@@ -204,30 +150,43 @@ bool UniValue::pushKVs(const UniValue& obj)
if (typ != VOBJ || obj.typ != VOBJ)
return false;
- for (unsigned int i = 0; i < obj.keys.size(); i++) {
- keys.push_back(obj.keys[i]);
- values.push_back(obj.values.at(i));
- }
+ for (size_t i = 0; i < obj.keys.size(); i++)
+ __pushKV(obj.keys[i], obj.values.at(i));
return true;
}
-int UniValue::findKey(const std::string& key) const
+void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
+{
+ if (typ != VOBJ)
+ return;
+
+ kv.clear();
+ for (size_t i = 0; i < keys.size(); i++)
+ kv[keys[i]] = values[i];
+}
+
+bool UniValue::findKey(const std::string& key, size_t& retIdx) const
{
- for (unsigned int i = 0; i < keys.size(); i++) {
- if (keys[i] == key)
- return (int) i;
+ for (size_t i = 0; i < keys.size(); i++) {
+ if (keys[i] == key) {
+ retIdx = i;
+ return true;
+ }
}
- return -1;
+ return false;
}
-bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
+bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
{
+ if (typ != VOBJ)
+ return false;
+
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
it != t.end(); ++it) {
- int idx = findKey(it->first);
- if (idx < 0)
+ size_t idx = 0;
+ if (!findKey(it->first, idx))
return false;
if (values.at(idx).getType() != it->second)
@@ -242,14 +201,14 @@ const UniValue& UniValue::operator[](const std::string& key) const
if (typ != VOBJ)
return NullUniValue;
- int index = findKey(key);
- if (index < 0)
+ size_t index = 0;
+ if (!findKey(key, index))
return NullUniValue;
return values.at(index);
}
-const UniValue& UniValue::operator[](unsigned int index) const
+const UniValue& UniValue::operator[](size_t index) const
{
if (typ != VOBJ && typ != VARR)
return NullUniValue;
@@ -283,75 +242,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
return NullUniValue;
}
-const std::vector<std::string>& UniValue::getKeys() const
-{
- if (typ != VOBJ)
- throw std::runtime_error("JSON value is not an object as expected");
- return keys;
-}
-
-const std::vector<UniValue>& UniValue::getValues() const
-{
- if (typ != VOBJ && typ != VARR)
- throw std::runtime_error("JSON value is not an object or array as expected");
- return values;
-}
-
-bool UniValue::get_bool() const
-{
- if (typ != VBOOL)
- throw std::runtime_error("JSON value is not a boolean as expected");
- return getBool();
-}
-
-const std::string& UniValue::get_str() const
-{
- if (typ != VSTR)
- throw std::runtime_error("JSON value is not a string as expected");
- return getValStr();
-}
-
-int UniValue::get_int() const
-{
- if (typ != VNUM)
- throw std::runtime_error("JSON value is not an integer as expected");
- int32_t retval;
- if (!ParseInt32(getValStr(), &retval))
- throw std::runtime_error("JSON integer out of range");
- return retval;
-}
-
-int64_t UniValue::get_int64() const
-{
- if (typ != VNUM)
- throw std::runtime_error("JSON value is not an integer as expected");
- int64_t retval;
- if (!ParseInt64(getValStr(), &retval))
- throw std::runtime_error("JSON integer out of range");
- return retval;
-}
-
-double UniValue::get_real() const
-{
- if (typ != VNUM)
- throw std::runtime_error("JSON value is not a number as expected");
- double retval;
- if (!ParseDouble(getValStr(), &retval))
- throw std::runtime_error("JSON double out of range");
- return retval;
-}
-
-const UniValue& UniValue::get_obj() const
-{
- if (typ != VOBJ)
- throw std::runtime_error("JSON value is not an object as expected");
- return *this;
-}
-
-const UniValue& UniValue::get_array() const
-{
- if (typ != VARR)
- throw std::runtime_error("JSON value is not an array as expected");
- return *this;
-}
-
diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp
new file mode 100644
index 0000000000..eabcf2dad1
--- /dev/null
+++ b/src/univalue/lib/univalue_get.cpp
@@ -0,0 +1,147 @@
+// Copyright 2014 BitPay Inc.
+// Copyright 2015 Bitcoin Core Developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdexcept>
+#include <vector>
+#include <limits>
+#include <string>
+
+#include "univalue.h"
+
+namespace
+{
+static bool ParsePrechecks(const std::string& str)
+{
+ if (str.empty()) // No empty string allowed
+ return false;
+ if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
+ return false;
+ if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
+ return false;
+ return true;
+}
+
+bool ParseInt32(const std::string& str, int32_t *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ char *endp = NULL;
+ errno = 0; // strtol will not set errno if valid
+ long int n = strtol(str.c_str(), &endp, 10);
+ if(out) *out = (int32_t)n;
+ // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
+ // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
+ // platforms the size of these types may be different.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int32_t>::min() &&
+ n <= std::numeric_limits<int32_t>::max();
+}
+
+bool ParseInt64(const std::string& str, int64_t *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ char *endp = NULL;
+ errno = 0; // strtoll will not set errno if valid
+ long long int n = strtoll(str.c_str(), &endp, 10);
+ if(out) *out = (int64_t)n;
+ // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
+ // we still have to check that the returned value is within the range of an *int64_t*.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int64_t>::min() &&
+ n <= std::numeric_limits<int64_t>::max();
+}
+
+bool ParseDouble(const std::string& str, double *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
+ return false;
+ std::istringstream text(str);
+ text.imbue(std::locale::classic());
+ double result;
+ text >> result;
+ if(out) *out = result;
+ return text.eof() && !text.fail();
+}
+}
+
+const std::vector<std::string>& UniValue::getKeys() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return keys;
+}
+
+const std::vector<UniValue>& UniValue::getValues() const
+{
+ if (typ != VOBJ && typ != VARR)
+ throw std::runtime_error("JSON value is not an object or array as expected");
+ return values;
+}
+
+bool UniValue::get_bool() const
+{
+ if (typ != VBOOL)
+ throw std::runtime_error("JSON value is not a boolean as expected");
+ return getBool();
+}
+
+const std::string& UniValue::get_str() const
+{
+ if (typ != VSTR)
+ throw std::runtime_error("JSON value is not a string as expected");
+ return getValStr();
+}
+
+int UniValue::get_int() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int32_t retval;
+ if (!ParseInt32(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+int64_t UniValue::get_int64() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int64_t retval;
+ if (!ParseInt64(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+double UniValue::get_real() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not a number as expected");
+ double retval;
+ if (!ParseDouble(getValStr(), &retval))
+ throw std::runtime_error("JSON double out of range");
+ return retval;
+}
+
+const UniValue& UniValue::get_obj() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return *this;
+}
+
+const UniValue& UniValue::get_array() const
+{
+ if (typ != VARR)
+ throw std::runtime_error("JSON value is not an array as expected");
+ return *this;
+}
+
diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp
index 95bac6958d..ae75cb462a 100644
--- a/src/univalue/lib/univalue_read.cpp
+++ b/src/univalue/lib/univalue_read.cpp
@@ -43,21 +43,21 @@ static const char *hatoui(const char *first, const char *last,
}
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
- const char *raw)
+ const char *raw, const char *end)
{
tokenVal.clear();
consumed = 0;
const char *rawStart = raw;
- while ((*raw) && (json_isspace(*raw))) // skip whitespace
+ while (raw < end && (json_isspace(*raw))) // skip whitespace
raw++;
- switch (*raw) {
-
- case 0:
+ if (raw >= end)
return JTOK_NONE;
+ switch (*raw) {
+
case '{':
raw++;
consumed = (raw - rawStart);
@@ -127,40 +127,40 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
numStr += *raw; // copy first char
raw++;
- if ((*first == '-') && (!json_isdigit(*raw)))
+ if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
return JTOK_ERR;
- while ((*raw) && json_isdigit(*raw)) { // copy digits
+ while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
// part 2: frac
- if (*raw == '.') {
+ if (raw < end && *raw == '.') {
numStr += *raw; // copy .
raw++;
- if (!json_isdigit(*raw))
+ if (raw >= end || !json_isdigit(*raw))
return JTOK_ERR;
- while ((*raw) && json_isdigit(*raw)) { // copy digits
+ while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
}
// part 3: exp
- if (*raw == 'e' || *raw == 'E') {
+ if (raw < end && (*raw == 'e' || *raw == 'E')) {
numStr += *raw; // copy E
raw++;
- if (*raw == '-' || *raw == '+') { // copy +/-
+ if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
numStr += *raw;
raw++;
}
- if (!json_isdigit(*raw))
+ if (raw >= end || !json_isdigit(*raw))
return JTOK_ERR;
- while ((*raw) && json_isdigit(*raw)) { // copy digits
+ while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
@@ -177,13 +177,16 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
string valStr;
JSONUTF8StringFilter writer(valStr);
- while (*raw) {
- if ((unsigned char)*raw < 0x20)
+ while (true) {
+ if (raw >= end || (unsigned char)*raw < 0x20)
return JTOK_ERR;
else if (*raw == '\\') {
raw++; // skip backslash
+ if (raw >= end)
+ return JTOK_ERR;
+
switch (*raw) {
case '"': writer.push_back('\"'); break;
case '\\': writer.push_back('\\'); break;
@@ -196,7 +199,8 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
case 'u': {
unsigned int codepoint;
- if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
+ if (raw + 1 + 4 >= end ||
+ hatoui(raw + 1, raw + 1 + 4, codepoint) !=
raw + 1 + 4)
return JTOK_ERR;
writer.push_back_u(codepoint);
@@ -246,7 +250,7 @@ enum expect_bits {
#define setExpect(bit) (expectMask |= EXP_##bit)
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
-bool UniValue::read(const char *raw)
+bool UniValue::read(const char *raw, size_t size)
{
clear();
@@ -257,10 +261,11 @@ bool UniValue::read(const char *raw)
unsigned int consumed;
enum jtokentype tok = JTOK_NONE;
enum jtokentype last_tok = JTOK_NONE;
+ const char* end = raw + size;
do {
last_tok = tok;
- tok = getJsonToken(tokenVal, consumed, raw);
+ tok = getJsonToken(tokenVal, consumed, raw, end);
if (tok == JTOK_NONE || tok == JTOK_ERR)
return false;
raw += consumed;
@@ -371,9 +376,6 @@ bool UniValue::read(const char *raw)
case JTOK_KW_NULL:
case JTOK_KW_TRUE:
case JTOK_KW_FALSE: {
- if (!stack.size())
- return false;
-
UniValue tmpVal;
switch (tok) {
case JTOK_KW_NULL:
@@ -388,6 +390,11 @@ bool UniValue::read(const char *raw)
default: /* impossible */ break;
}
+ if (!stack.size()) {
+ *this = tmpVal;
+ break;
+ }
+
UniValue *top = stack.back();
top->values.push_back(tmpVal);
@@ -396,10 +403,12 @@ bool UniValue::read(const char *raw)
}
case JTOK_NUMBER: {
- if (!stack.size())
- return false;
-
UniValue tmpVal(VNUM, tokenVal);
+ if (!stack.size()) {
+ *this = tmpVal;
+ break;
+ }
+
UniValue *top = stack.back();
top->values.push_back(tmpVal);
@@ -408,17 +417,18 @@ bool UniValue::read(const char *raw)
}
case JTOK_STRING: {
- if (!stack.size())
- return false;
-
- UniValue *top = stack.back();
-
if (expect(OBJ_NAME)) {
+ UniValue *top = stack.back();
top->keys.push_back(tokenVal);
clearExpect(OBJ_NAME);
setExpect(COLON);
} else {
UniValue tmpVal(VSTR, tokenVal);
+ if (!stack.size()) {
+ *this = tmpVal;
+ break;
+ }
+ UniValue *top = stack.back();
top->values.push_back(tmpVal);
}
@@ -432,7 +442,7 @@ bool UniValue::read(const char *raw)
} while (!stack.empty ());
/* Check that nothing follows the initial construct (parsed above). */
- tok = getJsonToken(tokenVal, consumed, raw);
+ tok = getJsonToken(tokenVal, consumed, raw, end);
if (tok != JTOK_NONE)
return false;
diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h
index 0e330dce9c..20d4043009 100644
--- a/src/univalue/lib/univalue_utffilter.h
+++ b/src/univalue/lib/univalue_utffilter.h
@@ -13,7 +13,7 @@
class JSONUTF8StringFilter
{
public:
- JSONUTF8StringFilter(std::string &s):
+ explicit JSONUTF8StringFilter(std::string &s):
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
{
}
@@ -46,19 +46,19 @@ public:
}
}
// Write codepoint directly, possibly collating surrogate pairs
- void push_back_u(unsigned int codepoint)
+ void push_back_u(unsigned int codepoint_)
{
if (state) // Only accept full codepoints in open state
is_valid = false;
- if (codepoint >= 0xD800 && codepoint < 0xDC00) { // First half of surrogate pair
+ if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair
if (surpair) // Two subsequent surrogate pair openers - fail
is_valid = false;
else
- surpair = codepoint;
- } else if (codepoint >= 0xDC00 && codepoint < 0xE000) { // Second half of surrogate pair
+ surpair = codepoint_;
+ } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair
if (surpair) { // Open surrogate pair, expect second half
// Compute code point from UTF-16 surrogate pair
- append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint - 0xDC00));
+ append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00));
surpair = 0;
} else // Second half doesn't follow a first half - fail
is_valid = false;
@@ -66,7 +66,7 @@ public:
if (surpair) // First half of surrogate pair not followed by second - fail
is_valid = false;
else
- append_codepoint(codepoint);
+ append_codepoint(codepoint_);
}
}
// Check that we're in a state where the string can be ended
@@ -96,22 +96,22 @@ private:
// Two subsequent \u.... may have to be replaced with one actual codepoint.
unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0
- void append_codepoint(unsigned int codepoint)
+ void append_codepoint(unsigned int codepoint_)
{
- if (codepoint <= 0x7f)
- str.push_back((char)codepoint);
- else if (codepoint <= 0x7FF) {
- str.push_back((char)(0xC0 | (codepoint >> 6)));
- str.push_back((char)(0x80 | (codepoint & 0x3F)));
- } else if (codepoint <= 0xFFFF) {
- str.push_back((char)(0xE0 | (codepoint >> 12)));
- str.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
- str.push_back((char)(0x80 | (codepoint & 0x3F)));
- } else if (codepoint <= 0x1FFFFF) {
- str.push_back((char)(0xF0 | (codepoint >> 18)));
- str.push_back((char)(0x80 | ((codepoint >> 12) & 0x3F)));
- str.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
- str.push_back((char)(0x80 | (codepoint & 0x3F)));
+ if (codepoint_ <= 0x7f)
+ str.push_back((char)codepoint_);
+ else if (codepoint_ <= 0x7FF) {
+ str.push_back((char)(0xC0 | (codepoint_ >> 6)));
+ str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
+ } else if (codepoint_ <= 0xFFFF) {
+ str.push_back((char)(0xE0 | (codepoint_ >> 12)));
+ str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
+ str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
+ } else if (codepoint_ <= 0x1FFFFF) {
+ str.push_back((char)(0xF0 | (codepoint_ >> 18)));
+ str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F)));
+ str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
+ str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
}
}
};
diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp
index cfbdad3284..cf27835991 100644
--- a/src/univalue/lib/univalue_write.cpp
+++ b/src/univalue/lib/univalue_write.cpp
@@ -79,8 +79,6 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
s += values[i].write(prettyIndent, indentLevel + 1);
if (i != (values.size() - 1)) {
s += ",";
- if (prettyIndent)
- s += " ";
}
if (prettyIndent)
s += "\n";
diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore
index 3d9347fe7e..7b27cf0da2 100644
--- a/src/univalue/test/.gitignore
+++ b/src/univalue/test/.gitignore
@@ -1,4 +1,8 @@
+
+object
unitester
+test_json
+no_nul
*.trs
*.log
diff --git a/src/univalue/test/fail1.json b/src/univalue/test/fail1.json
index 6216b865f1..8feb01a6d0 100644
--- a/src/univalue/test/fail1.json
+++ b/src/univalue/test/fail1.json
@@ -1 +1 @@
-"A JSON payload should be an object or array, not a string." \ No newline at end of file
+"This is a string that never ends, yes it goes on and on, my friends.
diff --git a/src/univalue/test/fail42.json b/src/univalue/test/fail42.json
new file mode 100644
index 0000000000..9c7565adbd
--- /dev/null
+++ b/src/univalue/test/fail42.json
Binary files differ
diff --git a/src/univalue/test/fail44.json b/src/univalue/test/fail44.json
new file mode 100644
index 0000000000..80edceddf1
--- /dev/null
+++ b/src/univalue/test/fail44.json
@@ -0,0 +1 @@
+"This file ends without a newline or close-quote. \ No newline at end of file
diff --git a/src/univalue/test/no_nul.cpp b/src/univalue/test/no_nul.cpp
new file mode 100644
index 0000000000..83d292200b
--- /dev/null
+++ b/src/univalue/test/no_nul.cpp
@@ -0,0 +1,8 @@
+#include "univalue.h"
+
+int main (int argc, char *argv[])
+{
+ char buf[] = "___[1,2,3]___";
+ UniValue val;
+ return val.read(buf + 3, 7) ? 0 : 1;
+}
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
new file mode 100644
index 0000000000..02446292a1
--- /dev/null
+++ b/src/univalue/test/object.cpp
@@ -0,0 +1,395 @@
+// Copyright (c) 2014 BitPay Inc.
+// 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.
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+#include <map>
+#include <cassert>
+#include <stdexcept>
+#include <univalue.h>
+
+#define BOOST_FIXTURE_TEST_SUITE(a, b)
+#define BOOST_AUTO_TEST_CASE(funcName) void funcName()
+#define BOOST_AUTO_TEST_SUITE_END()
+#define BOOST_CHECK(expr) assert(expr)
+#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))
+#define BOOST_CHECK_THROW(stmt, excMatch) { \
+ try { \
+ (stmt); \
+ } catch (excMatch & e) { \
+ } catch (...) { \
+ assert(0); \
+ } \
+ }
+#define BOOST_CHECK_NO_THROW(stmt) { \
+ try { \
+ (stmt); \
+ } catch (...) { \
+ assert(0); \
+ } \
+ }
+
+BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(univalue_constructor)
+{
+ UniValue v1;
+ BOOST_CHECK(v1.isNull());
+
+ UniValue v2(UniValue::VSTR);
+ BOOST_CHECK(v2.isStr());
+
+ UniValue v3(UniValue::VSTR, "foo");
+ BOOST_CHECK(v3.isStr());
+ BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
+
+ UniValue numTest;
+ BOOST_CHECK(numTest.setNumStr("82"));
+ BOOST_CHECK(numTest.isNum());
+ BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
+
+ uint64_t vu64 = 82;
+ UniValue v4(vu64);
+ BOOST_CHECK(v4.isNum());
+ BOOST_CHECK_EQUAL(v4.getValStr(), "82");
+
+ int64_t vi64 = -82;
+ UniValue v5(vi64);
+ BOOST_CHECK(v5.isNum());
+ BOOST_CHECK_EQUAL(v5.getValStr(), "-82");
+
+ int vi = -688;
+ UniValue v6(vi);
+ BOOST_CHECK(v6.isNum());
+ BOOST_CHECK_EQUAL(v6.getValStr(), "-688");
+
+ double vd = -7.21;
+ UniValue v7(vd);
+ BOOST_CHECK(v7.isNum());
+ BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
+
+ std::string vs("yawn");
+ UniValue v8(vs);
+ BOOST_CHECK(v8.isStr());
+ BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
+
+ const char *vcs = "zappa";
+ UniValue v9(vcs);
+ BOOST_CHECK(v9.isStr());
+ BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
+}
+
+BOOST_AUTO_TEST_CASE(univalue_typecheck)
+{
+ UniValue v1;
+ BOOST_CHECK(v1.setNumStr("1"));
+ BOOST_CHECK(v1.isNum());
+ BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
+
+ UniValue v2;
+ BOOST_CHECK(v2.setBool(true));
+ BOOST_CHECK_EQUAL(v2.get_bool(), true);
+ BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);
+
+ UniValue v3;
+ BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
+ BOOST_CHECK(v3.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
+
+ UniValue v4;
+ BOOST_CHECK(v4.setNumStr("2147483648"));
+ BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
+ BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
+ BOOST_CHECK(v4.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v4.get_int(), 1000);
+ BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
+ BOOST_CHECK_EQUAL(v4.get_real(), 1000);
+ BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);
+
+ UniValue v5;
+ BOOST_CHECK(v5.read("[true, 10]"));
+ BOOST_CHECK_NO_THROW(v5.get_array());
+ std::vector<UniValue> vals = v5.getValues();
+ BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);
+ BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
+
+ BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
+ BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(univalue_set)
+{
+ UniValue v(UniValue::VSTR, "foo");
+ v.clear();
+ BOOST_CHECK(v.isNull());
+ BOOST_CHECK_EQUAL(v.getValStr(), "");
+
+ BOOST_CHECK(v.setObject());
+ BOOST_CHECK(v.isObject());
+ BOOST_CHECK_EQUAL(v.size(), 0);
+ BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
+ BOOST_CHECK(v.empty());
+
+ BOOST_CHECK(v.setArray());
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.size(), 0);
+
+ BOOST_CHECK(v.setStr("zum"));
+ BOOST_CHECK(v.isStr());
+ BOOST_CHECK_EQUAL(v.getValStr(), "zum");
+
+ BOOST_CHECK(v.setFloat(-1.01));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
+
+ BOOST_CHECK(v.setInt((int)1023));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "1023");
+
+ BOOST_CHECK(v.setInt((int64_t)-1023LL));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
+
+ BOOST_CHECK(v.setInt((uint64_t)1023ULL));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "1023");
+
+ BOOST_CHECK(v.setNumStr("-688"));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-688");
+
+ BOOST_CHECK(v.setBool(false));
+ BOOST_CHECK_EQUAL(v.isBool(), true);
+ BOOST_CHECK_EQUAL(v.isTrue(), false);
+ BOOST_CHECK_EQUAL(v.isFalse(), true);
+ BOOST_CHECK_EQUAL(v.getBool(), false);
+
+ BOOST_CHECK(v.setBool(true));
+ BOOST_CHECK_EQUAL(v.isBool(), true);
+ BOOST_CHECK_EQUAL(v.isTrue(), true);
+ BOOST_CHECK_EQUAL(v.isFalse(), false);
+ BOOST_CHECK_EQUAL(v.getBool(), true);
+
+ BOOST_CHECK(!v.setNumStr("zombocom"));
+
+ BOOST_CHECK(v.setNull());
+ BOOST_CHECK(v.isNull());
+}
+
+BOOST_AUTO_TEST_CASE(univalue_array)
+{
+ UniValue arr(UniValue::VARR);
+
+ UniValue v((int64_t)1023LL);
+ BOOST_CHECK(arr.push_back(v));
+
+ std::string vStr("zippy");
+ BOOST_CHECK(arr.push_back(vStr));
+
+ const char *s = "pippy";
+ BOOST_CHECK(arr.push_back(s));
+
+ std::vector<UniValue> vec;
+ v.setStr("boing");
+ vec.push_back(v);
+
+ v.setStr("going");
+ vec.push_back(v);
+
+ BOOST_CHECK(arr.push_backV(vec));
+
+ BOOST_CHECK(arr.push_back((uint64_t) 400ULL));
+ BOOST_CHECK(arr.push_back((int64_t) -400LL));
+ BOOST_CHECK(arr.push_back((int) -401));
+ BOOST_CHECK(arr.push_back(-40.1));
+
+ BOOST_CHECK_EQUAL(arr.empty(), false);
+ BOOST_CHECK_EQUAL(arr.size(), 9);
+
+ BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
+ BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
+ BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
+ BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
+ BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
+ BOOST_CHECK_EQUAL(arr[5].getValStr(), "400");
+ BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400");
+ BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401");
+ BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1");
+
+ BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
+
+ arr.clear();
+ BOOST_CHECK(arr.empty());
+ BOOST_CHECK_EQUAL(arr.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(univalue_object)
+{
+ UniValue obj(UniValue::VOBJ);
+ std::string strKey, strVal;
+ UniValue v;
+
+ strKey = "age";
+ v.setInt(100);
+ BOOST_CHECK(obj.pushKV(strKey, v));
+
+ strKey = "first";
+ strVal = "John";
+ BOOST_CHECK(obj.pushKV(strKey, strVal));
+
+ strKey = "last";
+ const char *cVal = "Smith";
+ BOOST_CHECK(obj.pushKV(strKey, cVal));
+
+ strKey = "distance";
+ BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
+
+ strKey = "time";
+ BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
+
+ strKey = "calories";
+ BOOST_CHECK(obj.pushKV(strKey, (int) 12));
+
+ strKey = "temperature";
+ BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
+
+ UniValue obj2(UniValue::VOBJ);
+ BOOST_CHECK(obj2.pushKV("cat1", 9000));
+ BOOST_CHECK(obj2.pushKV("cat2", 12345));
+
+ BOOST_CHECK(obj.pushKVs(obj2));
+
+ BOOST_CHECK_EQUAL(obj.empty(), false);
+ BOOST_CHECK_EQUAL(obj.size(), 9);
+
+ BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
+ BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
+ BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
+ BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
+ BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
+ BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
+ BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
+ BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
+ BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
+
+ BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
+
+ BOOST_CHECK(obj.exists("age"));
+ BOOST_CHECK(obj.exists("first"));
+ BOOST_CHECK(obj.exists("last"));
+ BOOST_CHECK(obj.exists("distance"));
+ BOOST_CHECK(obj.exists("time"));
+ BOOST_CHECK(obj.exists("calories"));
+ BOOST_CHECK(obj.exists("temperature"));
+ BOOST_CHECK(obj.exists("cat1"));
+ BOOST_CHECK(obj.exists("cat2"));
+
+ BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
+
+ std::map<std::string, UniValue::VType> objTypes;
+ objTypes["age"] = UniValue::VNUM;
+ objTypes["first"] = UniValue::VSTR;
+ objTypes["last"] = UniValue::VSTR;
+ objTypes["distance"] = UniValue::VNUM;
+ objTypes["time"] = UniValue::VNUM;
+ objTypes["calories"] = UniValue::VNUM;
+ objTypes["temperature"] = UniValue::VNUM;
+ objTypes["cat1"] = UniValue::VNUM;
+ objTypes["cat2"] = UniValue::VNUM;
+ BOOST_CHECK(obj.checkObject(objTypes));
+
+ objTypes["cat2"] = UniValue::VSTR;
+ BOOST_CHECK(!obj.checkObject(objTypes));
+
+ obj.clear();
+ BOOST_CHECK(obj.empty());
+ BOOST_CHECK_EQUAL(obj.size(), 0);
+ BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
+
+ BOOST_CHECK_EQUAL(obj.setObject(), true);
+ UniValue uv;
+ uv.setInt(42);
+ obj.__pushKV("age", uv);
+ BOOST_CHECK_EQUAL(obj.size(), 1);
+ BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42");
+
+ uv.setInt(43);
+ obj.pushKV("age", uv);
+ BOOST_CHECK_EQUAL(obj.size(), 1);
+ BOOST_CHECK_EQUAL(obj["age"].getValStr(), "43");
+
+ obj.pushKV("name", "foo bar");
+
+ std::map<std::string,UniValue> kv;
+ obj.getObjMap(kv);
+ BOOST_CHECK_EQUAL(kv["age"].getValStr(), "43");
+ BOOST_CHECK_EQUAL(kv["name"].getValStr(), "foo bar");
+
+}
+
+static const char *json1 =
+"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
+
+BOOST_AUTO_TEST_CASE(univalue_readwrite)
+{
+ UniValue v;
+ BOOST_CHECK(v.read(json1));
+
+ std::string strJson1(json1);
+ BOOST_CHECK(v.read(strJson1));
+
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.size(), 2);
+
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
+
+ UniValue obj = v[1];
+ BOOST_CHECK(obj.isObject());
+ BOOST_CHECK_EQUAL(obj.size(), 3);
+
+ BOOST_CHECK(obj["key1"].isStr());
+ std::string correctValue("str");
+ correctValue.push_back('\0');
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
+ BOOST_CHECK(obj["key2"].isNum());
+ BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
+ BOOST_CHECK(obj["key3"].isObject());
+
+ BOOST_CHECK_EQUAL(strJson1, v.write());
+
+ /* Check for (correctly reporting) a parsing error if the initial
+ JSON construct is followed by more stuff. Note that whitespace
+ is, of course, exempt. */
+
+ BOOST_CHECK(v.read(" {}\n "));
+ BOOST_CHECK(v.isObject());
+ BOOST_CHECK(v.read(" []\n "));
+ BOOST_CHECK(v.isArray());
+
+ BOOST_CHECK(!v.read("@{}"));
+ BOOST_CHECK(!v.read("{} garbage"));
+ BOOST_CHECK(!v.read("[]{}"));
+ BOOST_CHECK(!v.read("{}[]"));
+ BOOST_CHECK(!v.read("{} 42"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+int main (int argc, char *argv[])
+{
+ univalue_constructor();
+ univalue_typecheck();
+ univalue_set();
+ univalue_array();
+ univalue_object();
+ univalue_readwrite();
+ return 0;
+}
+
diff --git a/src/univalue/test/round3.json b/src/univalue/test/round3.json
new file mode 100644
index 0000000000..7182dc2f9b
--- /dev/null
+++ b/src/univalue/test/round3.json
@@ -0,0 +1 @@
+"abcdefghijklmnopqrstuvwxyz"
diff --git a/src/univalue/test/round4.json b/src/univalue/test/round4.json
new file mode 100644
index 0000000000..7f8f011eb7
--- /dev/null
+++ b/src/univalue/test/round4.json
@@ -0,0 +1 @@
+7
diff --git a/src/univalue/test/round5.json b/src/univalue/test/round5.json
new file mode 100644
index 0000000000..27ba77ddaf
--- /dev/null
+++ b/src/univalue/test/round5.json
@@ -0,0 +1 @@
+true
diff --git a/src/univalue/test/round6.json b/src/univalue/test/round6.json
new file mode 100644
index 0000000000..c508d5366f
--- /dev/null
+++ b/src/univalue/test/round6.json
@@ -0,0 +1 @@
+false
diff --git a/src/univalue/test/round7.json b/src/univalue/test/round7.json
new file mode 100644
index 0000000000..19765bd501
--- /dev/null
+++ b/src/univalue/test/round7.json
@@ -0,0 +1 @@
+null
diff --git a/src/univalue/test/test_json.cpp b/src/univalue/test/test_json.cpp
new file mode 100644
index 0000000000..2943bae2b1
--- /dev/null
+++ b/src/univalue/test/test_json.cpp
@@ -0,0 +1,24 @@
+// Test program that can be called by the JSON test suite at
+// https://github.com/nst/JSONTestSuite.
+//
+// It reads JSON input from stdin and exits with code 0 if it can be parsed
+// successfully. It also pretty prints the parsed JSON value to stdout.
+
+#include <iostream>
+#include <string>
+#include "univalue.h"
+
+using namespace std;
+
+int main (int argc, char *argv[])
+{
+ UniValue val;
+ if (val.read(string(istreambuf_iterator<char>(cin),
+ istreambuf_iterator<char>()))) {
+ cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl;
+ return 0;
+ } else {
+ cerr << "JSON Parse Error." << endl;
+ return 1;
+ }
+}
diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp
index 05f3842cd1..2c37794a4b 100644
--- a/src/univalue/test/unitester.cpp
+++ b/src/univalue/test/unitester.cpp
@@ -113,6 +113,8 @@ static const char *filenames[] = {
"fail39.json", // invalid unicode: only second half of surrogate pair
"fail40.json", // invalid unicode: broken UTF-8
"fail41.json", // invalid unicode: unfinished UTF-8
+ "fail42.json", // valid json with garbage following a nul byte
+ "fail44.json", // unterminated string
"fail3.json",
"fail4.json", // extra comma
"fail5.json",
@@ -125,6 +127,11 @@ static const char *filenames[] = {
"pass3.json",
"round1.json", // round-trip test
"round2.json", // unicode
+ "round3.json", // bare string
+ "round4.json", // bare number
+ "round5.json", // bare true
+ "round6.json", // bare false
+ "round7.json", // bare null
};
// Test \u handling
diff --git a/src/util.cpp b/src/util.cpp
index ba563478fa..a3e4b0acfb 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,18 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
-#endif
-
-#include "util.h"
+#include <util.h>
-#include "chainparamsbase.h"
-#include "fs.h"
-#include "random.h"
-#include "serialize.h"
-#include "utilstrencodings.h"
-#include "utiltime.h"
+#include <chainparamsbase.h>
+#include <random.h>
+#include <serialize.h>
+#include <utilstrencodings.h>
#include <stdarg.h>
@@ -89,6 +83,7 @@ const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
+const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
ArgsManager gArgs;
bool fPrintToConsole = false;
@@ -189,26 +184,40 @@ static void DebugPrintInit()
vMsgsBeforeOpenLog = new std::list<std::string>;
}
-void OpenDebugLog()
+fs::path GetDebugLogPath()
+{
+ fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ if (logfile.is_absolute()) {
+ return logfile;
+ } else {
+ return GetDataDir() / logfile;
+ }
+}
+
+bool OpenDebugLog()
{
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
assert(fileout == nullptr);
assert(vMsgsBeforeOpenLog);
- fs::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = GetDebugLogPath();
+
fileout = fsbridge::fopen(pathDebug, "a");
- if (fileout) {
- setbuf(fileout, nullptr); // unbuffered
- // dump buffered messages from before we opened the log
- while (!vMsgsBeforeOpenLog->empty()) {
- FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
- vMsgsBeforeOpenLog->pop_front();
- }
+ if (!fileout) {
+ return false;
+ }
+
+ setbuf(fileout, nullptr); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
}
delete vMsgsBeforeOpenLog;
vMsgsBeforeOpenLog = nullptr;
+ return true;
}
struct CLogCategoryDesc
@@ -220,6 +229,7 @@ struct CLogCategoryDesc
const CLogCategoryDesc LogCategories[] =
{
{BCLog::NONE, "0"},
+ {BCLog::NONE, "none"},
{BCLog::NET, "net"},
{BCLog::TOR, "tor"},
{BCLog::MEMPOOL, "mempool"},
@@ -354,7 +364,7 @@ int LogPrintStr(const std::string &str)
// reopen the log file, if requested
if (fReopenDebugLog) {
fReopenDebugLog = false;
- fs::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = GetDebugLogPath();
if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
setbuf(fileout, nullptr); // unbuffered
}
@@ -419,49 +429,48 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
}
}
-std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)
+std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
{
LOCK(cs_args);
- if (IsArgSet(strArg))
- return mapMultiArgs.at(strArg);
+ auto it = mapMultiArgs.find(strArg);
+ if (it != mapMultiArgs.end()) return it->second;
return {};
}
-bool ArgsManager::IsArgSet(const std::string& strArg)
+bool ArgsManager::IsArgSet(const std::string& strArg) const
{
LOCK(cs_args);
return mapArgs.count(strArg);
}
-std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)
+std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return mapArgs[strArg];
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return it->second;
return strDefault;
}
-int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault)
+int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return atoi64(mapArgs[strArg]);
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return atoi64(it->second);
return nDefault;
}
-bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault)
+bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return InterpretBool(mapArgs[strArg]);
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return InterpretBool(it->second);
return fDefault;
}
bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return false;
+ if (IsArgSet(strArg)) return false;
ForceSetArg(strArg, strValue);
return true;
}
@@ -478,8 +487,7 @@ void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strV
{
LOCK(cs_args);
mapArgs[strArg] = strValue;
- mapMultiArgs[strArg].clear();
- mapMultiArgs[strArg].push_back(strValue);
+ mapMultiArgs[strArg] = {strValue};
}
@@ -576,7 +584,10 @@ const fs::path &GetDataDir(bool fNetSpecific)
if (fNetSpecific)
path /= BaseParams().DataDir();
- fs::create_directories(path);
+ if (fs::create_directories(path)) {
+ // This is the first run, create wallets subdirectory too
+ fs::create_directories(path / "wallets");
+ }
return path;
}
@@ -622,6 +633,9 @@ void ArgsManager::ReadConfigFile(const std::string& confPath)
}
// If datadir is changed in .conf file:
ClearDatadirCache();
+ if (!fs::is_directory(GetDataDir(false))) {
+ throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
+ }
}
#ifndef WIN32
@@ -772,7 +786,7 @@ void ShrinkDebugFile()
// Amount of debug.log to save at end when shrinking (must fit in memory)
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
// Scroll debug.log if it's getting too big
- fs::path pathLog = GetDataDir() / "debug.log";
+ fs::path pathLog = GetDebugLogPath();
FILE* file = fsbridge::fopen(pathLog, "r");
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
@@ -812,6 +826,7 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
void runCommand(const std::string& strCommand)
{
+ if (strCommand.empty()) return;
int nErr = ::system(strCommand.c_str());
if (nErr)
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
diff --git a/src/util.h b/src/util.h
index ead3d3d935..3cc4c26817 100644
--- a/src/util.h
+++ b/src/util.h
@@ -11,14 +11,14 @@
#define BITCOIN_UTIL_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "fs.h"
-#include "sync.h"
-#include "tinyformat.h"
-#include "utiltime.h"
+#include <compat.h>
+#include <fs.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <utiltime.h>
#include <atomic>
#include <exception>
@@ -28,6 +28,7 @@
#include <vector>
#include <boost/signals2/signal.hpp>
+#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
@@ -35,6 +36,7 @@ int64_t GetStartupTime();
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
+extern const char * const DEFAULT_DEBUGLOGFILE;
/** Signals for translation. */
class CTranslationInterface
@@ -132,6 +134,10 @@ template<typename T, typename... Args> static inline void MarkUsed(const T& t, c
MarkUsed(args...);
}
+// Be conservative when using LogPrintf/error or other things which
+// unconditionally log to debug.log! It should not be the case that an inbound
+// peer can fill up a users disk with debug.log entries.
+
#ifdef USE_COVERAGE
#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
@@ -179,7 +185,8 @@ void CreatePidFile(const fs::path &path, pid_t pid);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
-void OpenDebugLog();
+fs::path GetDebugLogPath();
+bool OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
@@ -195,13 +202,20 @@ inline bool IsSwitchChar(char c)
class ArgsManager
{
protected:
- CCriticalSection cs_args;
+ mutable CCriticalSection cs_args;
std::map<std::string, std::string> mapArgs;
- std::map<std::string, std::vector<std::string> > mapMultiArgs;
+ std::map<std::string, std::vector<std::string>> mapMultiArgs;
public:
void ParseParameters(int argc, const char*const argv[]);
void ReadConfigFile(const std::string& confPath);
- std::vector<std::string> GetArgs(const std::string& strArg);
+
+ /**
+ * Return a vector of strings of the given argument
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return command-line arguments
+ */
+ std::vector<std::string> GetArgs(const std::string& strArg) const;
/**
* Return true if the given argument has been manually set
@@ -209,7 +223,7 @@ public:
* @param strArg Argument to get (e.g. "-foo")
* @return true if the argument has been set
*/
- bool IsArgSet(const std::string& strArg);
+ bool IsArgSet(const std::string& strArg) const;
/**
* Return string argument or default value
@@ -218,7 +232,7 @@ public:
* @param strDefault (e.g. "1")
* @return command-line argument or default value
*/
- std::string GetArg(const std::string& strArg, const std::string& strDefault);
+ std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
/**
* Return integer argument or default value
@@ -227,7 +241,7 @@ public:
* @param nDefault (e.g. 1)
* @return command-line argument (0 if invalid number) or default value
*/
- int64_t GetArg(const std::string& strArg, int64_t nDefault);
+ int64_t GetArg(const std::string& strArg, int64_t nDefault) const;
/**
* Return boolean argument or default value
@@ -236,7 +250,7 @@ public:
* @param fDefault (true or false)
* @return command-line argument or default value
*/
- bool GetBoolArg(const std::string& strArg, bool fDefault);
+ bool GetBoolArg(const std::string& strArg, bool fDefault) const;
/**
* Set an argument if it doesn't already have a value
@@ -319,4 +333,11 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
std::string CopyrightHolders(const std::string& strPrefix);
+//! Substitute for C++14 std::make_unique.
+template <typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
#endif // BITCOIN_UTIL_H
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 6e6e33184e..656d7c51b7 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilmoneystr.h"
+#include <utilmoneystr.h>
-#include "primitives/transaction.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <primitives/transaction.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
std::string FormatMoney(const CAmount& n)
{
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index bc885ee167..b1a4499e90 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -12,7 +12,7 @@
#include <stdint.h>
#include <string>
-#include "amount.h"
+#include <amount.h>
/* Do not use these functions to represent or parse monetary amounts to or from
* JSON but use AmountFromValue and ValueFromAmount for that.
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index fd233f6757..d90713ed6a 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
+#include <utilstrencodings.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
#include <cstdlib>
#include <cstring>
@@ -65,6 +65,19 @@ bool IsHex(const std::string& str)
return (str.size() > 0) && (str.size()%2 == 0);
}
+bool IsHexNumber(const std::string& str)
+{
+ size_t starting_location = 0;
+ if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') {
+ starting_location = 2;
+ }
+ for (auto c : str.substr(starting_location)) {
+ if (HexDigit(c) < 0) return false;
+ }
+ // Return false for empty string or "0x".
+ return (str.size() > starting_location);
+}
+
std::vector<unsigned char> ParseHex(const char* psz)
{
// convert hex dump to vector
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 53da60e8f1..af33f0e5f8 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -38,7 +38,13 @@ std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
signed char HexDigit(char c);
+/* Returns true if each character in str is a hex character, and has an even
+ * number of hex digits.*/
bool IsHex(const std::string& str);
+/**
+* Return true if the string is a hex number, optionally prefixed with "0x"
+*/
+bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
@@ -143,4 +149,28 @@ bool TimingResistantEqual(const T& a, const T& b)
*/
bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
+/** Convert from one power-of-2 number base to another. */
+template<int frombits, int tobits, bool pad, typename O, typename I>
+bool ConvertBits(O& out, I it, I end) {
+ size_t acc = 0;
+ size_t bits = 0;
+ constexpr size_t maxv = (1 << tobits) - 1;
+ constexpr size_t max_acc = (1 << (frombits + tobits - 1)) - 1;
+ while (it != end) {
+ acc = ((acc << frombits) | *it) & max_acc;
+ bits += frombits;
+ while (bits >= tobits) {
+ bits -= tobits;
+ out.push_back((acc >> bits) & maxv);
+ }
+ ++it;
+ }
+ if (pad) {
+ if (bits) out.push_back((acc << (tobits - bits)) & maxv);
+ } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
+ return false;
+ }
+ return true;
+}
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index 4cc77dbfeb..ca11cf341f 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -4,10 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "utiltime.h"
+#include <utiltime.h>
#include <atomic>
diff --git a/src/validation.cpp b/src/validation.cpp
index 8bd23a0f1d..75c40b22fc 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -3,46 +3,43 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "validation.h"
-
-#include "arith_uint256.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "checkqueue.h"
-#include "consensus/consensus.h"
-#include "consensus/merkle.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "cuckoocache.h"
-#include "fs.h"
-#include "hash.h"
-#include "init.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "pow.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "reverse_iterator.h"
-#include "script/script.h"
-#include "script/sigcache.h"
-#include "script/standard.h"
-#include "timedata.h"
-#include "tinyformat.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "undo.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "versionbits.h"
-#include "warnings.h"
-
-#include <atomic>
+#include <validation.h>
+
+#include <arith_uint256.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <checkqueue.h>
+#include <consensus/consensus.h>
+#include <consensus/merkle.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <cuckoocache.h>
+#include <hash.h>
+#include <init.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <pow.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <reverse_iterator.h>
+#include <script/script.h>
+#include <script/sigcache.h>
+#include <script/standard.h>
+#include <timedata.h>
+#include <tinyformat.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <undo.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <warnings.h>
+
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
@@ -53,20 +50,162 @@
# error "Bitcoin cannot be compiled without assertions."
#endif
+#define MICRO 0.000001
+#define MILLI 0.001
+
/**
* Global state
*/
+namespace {
+ struct CBlockIndexWorkComparator
+ {
+ bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
+ // First sort by most total work, ...
+ if (pa->nChainWork > pb->nChainWork) return false;
+ if (pa->nChainWork < pb->nChainWork) return true;
+
+ // ... then by earliest time received, ...
+ if (pa->nSequenceId < pb->nSequenceId) return false;
+ if (pa->nSequenceId > pb->nSequenceId) return true;
+
+ // Use pointer address as tie breaker (should only happen with blocks
+ // loaded from disk, as those all have id 0).
+ if (pa < pb) return false;
+ if (pa > pb) return true;
+
+ // Identical blocks.
+ return false;
+ }
+ };
+} // anon namespace
+
+enum DisconnectResult
+{
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
+
+class ConnectTrace;
+
+/**
+ * CChainState stores and provides an API to update our local knowledge of the
+ * current best chain and header tree.
+ *
+ * It generally provides access to the current block tree, as well as functions
+ * to provide new data, which it will appropriately validate and incorporate in
+ * its state as necessary.
+ *
+ * Eventually, the API here is targeted at being exposed externally as a
+ * consumable libconsensus library, so any functions added must only call
+ * other class member functions, pure functions in other parts of the consensus
+ * library, callbacks via the validation interface, or read/write-to-disk
+ * functions (eventually this will also be via callbacks).
+ */
+class CChainState {
+private:
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
+ * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
+ * missing the data for the block.
+ */
+ std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+
+ /**
+ * Every received block is assigned a unique and increasing identifier, so we
+ * know which one to give priority in case of a fork.
+ */
+ CCriticalSection cs_nBlockSequenceId;
+ /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
+ int32_t nBlockSequenceId = 1;
+ /** Decreasing counter (used by subsequent preciousblock calls). */
+ int32_t nBlockReverseSequenceId = -1;
+ /** chainwork for the last block that preciousblock has been applied to. */
+ arith_uint256 nLastPreciousChainwork = 0;
+
+ /** In order to efficiently track invalidity of headers, we keep the set of
+ * blocks which we tried to connect and found to be invalid here (ie which
+ * were set to BLOCK_FAILED_VALID since the last restart). We can then
+ * walk this set and check if a new header is a descendant of something in
+ * this set, preventing us from having to walk mapBlockIndex when we try
+ * to connect a bad block and fail.
+ *
+ * While this is more complicated than marking everything which descends
+ * from an invalid block as invalid at the time we discover it to be
+ * invalid, doing so would require walking all of mapBlockIndex to find all
+ * descendants. Since this case should be very rare, keeping track of all
+ * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
+ * well.
+ *
+ * Because we already walk mapBlockIndex in height-order at startup, we go
+ * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
+ * instead of putting things in this set.
+ */
+ std::set<CBlockIndex*> g_failed_blocks;
+
+public:
+ CChain chainActive;
+ BlockMap mapBlockIndex;
+ std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ CBlockIndex *pindexBestInvalid = nullptr;
+
+ bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree);
+
+ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
+
+ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock);
+
+ // Block (dis)connection on a given view:
+ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
+ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false);
+
+ // Block disconnection on our pcoinsTip:
+ bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
+
+ // Manual block validity manipulation:
+ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
+ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
+ bool ResetBlockFailureFlags(CBlockIndex *pindex);
+
+ bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
+ bool RewindBlockIndex(const CChainParams& params);
+ bool LoadGenesisBlock(const CChainParams& chainparams);
+
+ void PruneBlockIndexCandidates();
+
+ void UnloadBlockIndex();
+
+private:
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
+
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block);
+ /** Create a new block index entry for a given block hash */
+ CBlockIndex * InsertBlockIndex(const uint256& hash);
+ void CheckBlockIndex(const Consensus::Params& consensusParams);
+
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
+ CBlockIndex* FindMostWorkChain();
+ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
+
+
+ bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params);
+} g_chainstate;
+
+
CCriticalSection cs_main;
-BlockMap mapBlockIndex;
-CChain chainActive;
+BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
+CChain& chainActive = g_chainstate.chainActive;
CBlockIndex *pindexBestHeader = nullptr;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
std::atomic_bool fImporting(false);
-bool fReindex = false;
+std::atomic_bool fReindex(false);
bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
@@ -80,6 +219,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
uint256 hashAssumeValid;
+arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -87,8 +227,6 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CBlockPolicyEstimator feeEstimator;
CTxMemPool mempool(&feeEstimator);
-static void CheckBlockIndex(const Consensus::Params& consensusParams);
-
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
@@ -96,40 +234,12 @@ const std::string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff
namespace {
+ CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
- struct CBlockIndexWorkComparator
- {
- bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
- // First sort by most total work, ...
- if (pa->nChainWork > pb->nChainWork) return false;
- if (pa->nChainWork < pb->nChainWork) return true;
-
- // ... then by earliest time received, ...
- if (pa->nSequenceId < pb->nSequenceId) return false;
- if (pa->nSequenceId > pb->nSequenceId) return true;
-
- // Use pointer address as tie breaker (should only happen with blocks
- // loaded from disk, as those all have id 0).
- if (pa < pb) return false;
- if (pa > pb) return true;
-
- // Identical blocks.
- return false;
- }
- };
-
- CBlockIndex *pindexBestInvalid;
-
- /**
- * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
- * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
- * missing the data for the block.
- */
- std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data.
*/
- std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = g_chainstate.mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -140,18 +250,6 @@ namespace {
*/
bool fCheckForPruning = false;
- /**
- * Every received block is assigned a unique and increasing identifier, so we
- * know which one to give priority in case of a fork.
- */
- CCriticalSection cs_nBlockSequenceId;
- /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
- int32_t nBlockSequenceId = 1;
- /** Decreasing counter (used by subsequent preciousblock calls). */
- int32_t nBlockReverseSequenceId = -1;
- /** chainwork for the last block that preciousblock has been applied to. */
- arith_uint256 nLastPreciousChainwork = 0;
-
/** Dirty block index entries. */
std::set<CBlockIndex*> setDirtyBlockIndex;
@@ -177,9 +275,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis();
}
-CCoinsViewDB *pcoinsdbview = nullptr;
-CCoinsViewCache *pcoinsTip = nullptr;
-CBlockTreeDB *pblocktree = nullptr;
+std::unique_ptr<CCoinsViewDB> pcoinsdbview;
+std::unique_ptr<CCoinsViewCache> pcoinsTip;
+std::unique_ptr<CBlockTreeDB> pblocktree;
enum FlushStateMode {
FLUSH_STATE_NONE,
@@ -215,7 +313,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
// IsFinalTx() with one more than chainActive.Height().
const int nBlockHeight = chainActive.Height() + 1;
- // BIP113 will require that time-locked transactions have nLockTime set to
+ // BIP113 requires that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
@@ -251,6 +349,8 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
+ assert(tip != nullptr);
+
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
@@ -269,7 +369,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
}
else {
// pcoinsTip contains the UTXO set for chainActive.Tip()
- CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
@@ -378,7 +478,9 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
- if (!fAddToMempool || (*it)->IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, *it, false, nullptr, nullptr, true)) {
+ if (!fAddToMempool || (*it)->IsCoinBase() ||
+ !AcceptToMemoryPool(mempool, stateDummy, *it, nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
// If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans).
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
@@ -396,7 +498,7 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
mempool.UpdateTransactionsFromBlock(vHashUpdate);
// We also need to remove any now-immature transactions
- mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ mempool.removeForReorg(pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
// Re-limit mempool size, in case we added any transactions
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
}
@@ -437,9 +539,9 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, txdata);
}
-static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
+static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
+ bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
{
const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
@@ -526,11 +628,10 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
CCoinsView dummy;
CCoinsViewCache view(&dummy);
- CAmount nValueIn = 0;
LockPoints lp;
{
LOCK(pool.cs);
- CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
view.SetBackend(viewMemPool);
// do all inputs exist?
@@ -557,8 +658,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Bring the best block into scope
view.GetBestBlock();
- nValueIn = view.GetValueIn(tx);
-
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
@@ -569,6 +668,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// CoinsViewCache instead of create its own
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
+
+ } // end LOCK(pool.cs)
+
+ CAmount nFees = 0;
+ if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) {
+ return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
}
// Check for non-standard pay-to-script-hash in inputs
@@ -581,8 +686,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
- CAmount nValueOut = tx.GetValueOut();
- CAmount nFees = nValueIn-nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees;
pool.ApplyDelta(hash, nModifiedFees);
@@ -612,12 +715,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
strprintf("%d", nSigOpsCost));
CAmount mempoolRejectFee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
- if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
+ if (!bypass_limits && mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
}
// No transactions are allowed below minRelayTxFee except from disconnected blocks
- if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
+ if (!bypass_limits && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
}
@@ -849,17 +952,18 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
- // This transaction should only count for fee estimation if it isn't a
- // BIP 125 replacement transaction (may not be widely supported), the
- // node is not behind, and the transaction is not dependent on any other
- // transactions in the mempool.
- bool validForFeeEstimation = !fReplacementTransaction && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
+ // This transaction should only count for fee estimation if:
+ // - it isn't a BIP 125 replacement transaction (may not be widely supported)
+ // - it's not being readded during a reorg which bypasses typical mempool fee limits
+ // - the node is not behind
+ // - the transaction is not dependent on any other transactions in the mempool
+ bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation);
// trim mempool and check if tx was trimmed
- if (!fOverrideMempoolLimit) {
+ if (!bypass_limits) {
LimitMempoolSize(pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
if (!pool.exists(hash))
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
@@ -872,12 +976,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
/** (try to) add transaction to memory pool with a specified acceptance time **/
-static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
+static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool bypass_limits, const CAmount nAbsurdFee)
{
std::vector<COutPoint> coins_to_uncache;
- bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache);
+ bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache);
if (!res) {
for (const COutPoint& hashTx : coins_to_uncache)
pcoinsTip->Uncache(hashTx);
@@ -888,52 +992,59 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
return res;
}
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
- bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool bypass_limits, const CAmount nAbsurdFee)
{
const CChainParams& chainparams = Params();
- return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee);
+ return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, pfMissingInputs, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee);
}
-/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
-bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
+/**
+ * Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock.
+ * If blockIndex is provided, the transaction is fetched from the corresponding block.
+ */
+bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, bool fAllowSlow, CBlockIndex* blockIndex)
{
- CBlockIndex *pindexSlow = nullptr;
+ CBlockIndex* pindexSlow = blockIndex;
LOCK(cs_main);
- CTransactionRef ptx = mempool.get(hash);
- if (ptx)
- {
- txOut = ptx;
- return true;
- }
+ if (!blockIndex) {
+ CTransactionRef ptx = mempool.get(hash);
+ if (ptx) {
+ txOut = ptx;
+ return true;
+ }
- if (fTxIndex) {
- CDiskTxPos postx;
- if (pblocktree->ReadTxIndex(hash, postx)) {
- CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
- if (file.IsNull())
- return error("%s: OpenBlockFile failed", __func__);
- CBlockHeader header;
- try {
- file >> header;
- fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
- file >> txOut;
- } catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ if (fTxIndex) {
+ CDiskTxPos postx;
+ if (pblocktree->ReadTxIndex(hash, postx)) {
+ CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
+ if (file.IsNull())
+ return error("%s: OpenBlockFile failed", __func__);
+ CBlockHeader header;
+ try {
+ file >> header;
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
+ file >> txOut;
+ } catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+ hashBlock = header.GetHash();
+ if (txOut->GetHash() != hash)
+ return error("%s: txid mismatch", __func__);
+ return true;
}
- hashBlock = header.GetHash();
- if (txOut->GetHash() != hash)
- return error("%s: txid mismatch", __func__);
- return true;
+
+ // transaction not found in index, nothing more can be done
+ return false;
}
- }
- if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
- const Coin& coin = AccessByTxid(*pcoinsTip, hash);
- if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
+ if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
+ const Coin& coin = AccessByTxid(*pcoinsTip, hash);
+ if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
+ }
}
if (pindexSlow) {
@@ -1032,8 +1143,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
bool IsInitialBlockDownload()
{
- const CChainParams& chainParams = Params();
-
// Once this function has returned false, it must remain false.
static std::atomic<bool> latchToFalse{false};
// Optimization: pre-test latch before taking the lock.
@@ -1047,7 +1156,7 @@ bool IsInitialBlockDownload()
return true;
if (chainActive.Tip() == nullptr)
return true;
- if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
+ if (chainActive.Tip()->nChainWork < nMinimumChainWork)
return true;
if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
@@ -1166,9 +1275,10 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
CheckForkWarningConditions();
}
-void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
+void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
+ g_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -1199,7 +1309,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
- return VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error);
+ return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error);
}
int GetSpendHeight(const CCoinsViewCache& inputs)
@@ -1240,9 +1350,6 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
{
if (!tx.IsCoinBase())
{
- if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
- return false;
-
if (pvChecks)
pvChecks->reserve(tx.vin.size());
@@ -1281,11 +1388,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// a sanity check that our caching is not introducing consensus
// failures through additional data in, eg, the coins being
// spent being checked as a part of CScriptCheck.
- const CScript& scriptPubKey = coin.out.scriptPubKey;
- const CAmount amount = coin.out.nValue;
// Verify signature
- CScriptCheck check(scriptPubKey, amount, tx, i, flags, cacheSigStore, &txdata);
+ CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1297,7 +1402,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check2(scriptPubKey, amount, tx, i,
+ CScriptCheck check2(coin.out, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
@@ -1353,8 +1458,13 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
return true;
}
-bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
+static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
{
+ CDiskBlockPos pos = pindex->GetUndoPos();
+ if (pos.IsNull()) {
+ return error("%s: no undo data available", __func__);
+ }
+
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
@@ -1364,7 +1474,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
uint256 hashChecksum;
CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
try {
- verifier << hashBlock;
+ verifier << pindex->pprev->GetBlockHash();
verifier >> blockundo;
filein >> hashChecksum;
}
@@ -1399,13 +1509,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
} // namespace
-enum DisconnectResult
-{
- DISCONNECT_OK, // All good.
- DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
- DISCONNECT_FAILED // Something else went wrong.
-};
-
/**
* Restore the UTXO in a Coin at a given COutPoint
* @param undo The Coin to be restored.
@@ -1442,17 +1545,12 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
* When FAILED is returned, view is left in an indeterminate state. */
-static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
+DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
{
bool fClean = true;
CBlockUndo blockUndo;
- CDiskBlockPos pos = pindex->GetUndoPos();
- if (pos.IsNull()) {
- error("DisconnectBlock(): no undo data available");
- return DISCONNECT_FAILED;
- }
- if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) {
+ if (!UndoReadFromDisk(blockUndo, pindex)) {
error("DisconnectBlock(): failure reading undo data");
return DISCONNECT_FAILED;
}
@@ -1529,6 +1627,45 @@ void static FlushBlockFile(bool fFinalize = false)
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
+static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
+{
+ // Write undo information to disk
+ if (pindex->GetUndoPos().IsNull()) {
+ CDiskBlockPos _pos;
+ if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
+ return error("ConnectBlock(): FindUndoPos failed");
+ if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
+ return AbortNode(state, "Failed to write undo data");
+
+ // update nUndoPos in block index
+ pindex->nUndoPos = _pos.nPos;
+ pindex->nStatus |= BLOCK_HAVE_UNDO;
+ setDirtyBlockIndex.insert(pindex);
+ }
+
+ return true;
+}
+
+static bool WriteTxIndexDataForBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex)
+{
+ if (!fTxIndex) return true;
+
+ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
+ std::vector<std::pair<uint256, CDiskTxPos> > vPos;
+ vPos.reserve(block.vtx.size());
+ for (const CTransactionRef& tx : block.vtx)
+ {
+ vPos.push_back(std::make_pair(tx->GetHash(), pos));
+ pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION);
+ }
+
+ if (!pblocktree->WriteTxIndex(vPos)) {
+ return AbortNode(state, "Failed to write transaction index");
+ }
+
+ return true;
+}
+
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
void ThreadScriptCheck() {
@@ -1563,7 +1700,7 @@ private:
int bit;
public:
- WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
+ explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); }
@@ -1584,11 +1721,12 @@ static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
AssertLockHeld(cs_main);
- // BIP16 didn't become active until Apr 1 2012
- int64_t nBIP16SwitchTime = 1333238400;
- bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
+ unsigned int flags = SCRIPT_VERIFY_NONE;
- unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
+ // Start enforcing P2SH (BIP16)
+ if (pindex->nHeight >= consensusparams.BIP16Height) {
+ flags |= SCRIPT_VERIFY_P2SH;
+ }
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
@@ -1623,12 +1761,13 @@ static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
+static int64_t nBlocksTotal = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */
-static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false)
+bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
{
AssertLockHeld(cs_main);
assert(pindex);
@@ -1638,6 +1777,18 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
+ // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
+ // ContextualCheckBlockHeader() here. This means that if we add a new
+ // consensus rule that is enforced in one of those two functions, then we
+ // may have let in a block that violates the rule prior to updating the
+ // software, and we would NOT be enforcing the rule here. Fully solving
+ // upgrade from one software version to the next after a consensus rule
+ // change is potentially tricky and issue-specific (see RewindBlockIndex()
+ // for one general approach that was used for BIP 141 deployment).
+ // Also, currently the rule against blocks more than 2 hours in the future
+ // is enforced in ContextualCheckBlockHeader(); we wouldn't want to
+ // re-enforce that rule here (at least until we make it impossible for
+ // GetAdjustedTime() to go backward).
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck))
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
@@ -1653,6 +1804,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
return true;
}
+ nBlocksTotal++;
+
bool fScriptChecks = true;
if (!hashAssumeValid.IsNull()) {
// We've been configured with the hash of a block which has been externally verified to have a valid history.
@@ -1664,7 +1817,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (it != mapBlockIndex.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
- pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ pindexBestHeader->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
// The equivalent time check discourages hash power from extorting the network via DOS attack
// into accepting an invalid block through telling users they must manually set assumevalid.
@@ -1680,7 +1833,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
}
int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;
- LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
+ LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -1704,6 +1857,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
// before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further
// duplicate transactions descending from the known pairs either.
// If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
+ assert(pindex->pprev);
CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
@@ -1729,7 +1883,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus());
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
- LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
CBlockUndo blockundo;
@@ -1739,9 +1893,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
CAmount nFees = 0;
int nInputs = 0;
int64_t nSigOpsCost = 0;
- CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
- std::vector<std::pair<uint256, CDiskTxPos> > vPos;
- vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
std::vector<PrecomputedTransactionData> txdata;
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
@@ -1753,9 +1904,15 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (!tx.IsCoinBase())
{
- if (!view.HaveInputs(tx))
- return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
- REJECT_INVALID, "bad-txns-inputs-missingorspent");
+ CAmount txfee = 0;
+ if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, txfee)) {
+ return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
+ }
+ nFees += txfee;
+ if (!MoneyRange(nFees)) {
+ return state.DoS(100, error("%s: accumulated fee in the block out of range.", __func__),
+ REJECT_INVALID, "bad-txns-accumulated-fee-outofrange");
+ }
// Check that transaction is BIP68 final
// BIP68 lock checks (as opposed to nLockTime checks) must
@@ -1783,8 +1940,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
- nFees += view.GetValueIn(tx)-tx.GetValueOut();
-
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr))
@@ -1798,12 +1953,9 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
-
- vPos.push_back(std::make_pair(tx.GetHash(), pos));
- pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward)
@@ -1815,42 +1967,31 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (!control.Wait())
return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
- LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);
+ LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
if (fJustCheck)
return true;
- // Write undo information to disk
- if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS))
- {
- if (pindex->GetUndoPos().IsNull()) {
- CDiskBlockPos _pos;
- if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
- return error("ConnectBlock(): FindUndoPos failed");
- if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
- return AbortNode(state, "Failed to write undo data");
-
- // update nUndoPos in block index
- pindex->nUndoPos = _pos.nPos;
- pindex->nStatus |= BLOCK_HAVE_UNDO;
- }
+ if (!WriteUndoDataForBlock(blockundo, state, pindex, chainparams))
+ return false;
+ if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
setDirtyBlockIndex.insert(pindex);
}
- if (fTxIndex)
- if (!pblocktree->WriteTxIndex(vPos))
- return AbortNode(state, "Failed to write transaction index");
+ if (!WriteTxIndexDataForBlock(block, state, pindex))
+ return false;
+ assert(pindex->phashBlock);
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5;
- LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeCallbacks * MICRO, nTimeCallbacks * MILLI / nBlocksTotal);
return true;
}
@@ -1992,10 +2133,8 @@ static void DoWarning(const std::string& strWarning)
}
}
-/** Update chainActive and related internal data structures. */
-void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
- chainActive.SetTip(pindexNew);
-
+/** Check warning conditions and do some notifications on new chain tip set. */
+void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainParams) {
// New best block
mempool.AddTransactionsUpdated(1);
@@ -2005,7 +2144,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
- const CBlockIndex* pindex = chainActive.Tip();
+ const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
@@ -2036,10 +2175,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
}
}
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
- log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
+ log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()),
+ GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
LogPrintf("\n");
@@ -2056,7 +2195,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
* disconnectpool (note that the caller is responsible for mempool consistency
* in any case).
*/
-bool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
+bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
{
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
@@ -2068,14 +2207,14 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
- CCoinsViewCache view(pcoinsTip);
+ CCoinsViewCache view(pcoinsTip.get());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
bool flushed = view.Flush();
assert(flushed);
}
- LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+ LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
@@ -2093,7 +2232,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
}
}
- // Update chainActive and related variables.
+ chainActive.SetTip(pindexDelete->pprev);
+
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
@@ -2135,7 +2275,7 @@ private:
CTxMemPool &pool;
public:
- ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
+ explicit ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
}
@@ -2178,7 +2318,7 @@ public:
*
* The block is added to connectTrace if connection succeeds.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
+bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
@@ -2196,9 +2336,9 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
// Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3;
- LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{
- CCoinsViewCache view(pcoinsTip);
+ CCoinsViewCache view(pcoinsTip.get());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) {
@@ -2207,26 +2347,27 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal);
bool flushed = view.Flush();
assert(flushed);
}
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
- LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
+ LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);
// Update chainActive & related variables.
+ chainActive.SetTip(pindexNew);
UpdateTip(pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
- LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
- LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal);
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
@@ -2236,7 +2377,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
* Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid).
*/
-static CBlockIndex* FindMostWorkChain() {
+CBlockIndex* CChainState::FindMostWorkChain() {
do {
CBlockIndex *pindexNew = nullptr;
@@ -2291,7 +2432,7 @@ static CBlockIndex* FindMostWorkChain() {
}
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
-static void PruneBlockIndexCandidates() {
+void CChainState::PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
@@ -2306,7 +2447,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
+bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -2376,7 +2517,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
// any disconnected transactions back to the mempool.
UpdateMempoolForReorg(disconnectpool, true);
}
- mempool.check(pcoinsTip);
+ mempool.check(pcoinsTip.get());
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
@@ -2413,7 +2554,7 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either nullptr or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
+bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
// Note that while we're often called here from ProcessNewBlock, this is
// far from a guarantee. Things in the P2P/RPC will often end up calling
// us in the middle of ProcessNewBlock - do not assume pblock is set
@@ -2457,7 +2598,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
assert(trace.pblock && trace.pindex);
- GetMainSignals().BlockConnected(trace.pblock, trace.pindex, *trace.conflictedTxs);
+ GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
}
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
@@ -2483,9 +2624,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return true;
}
+bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
+ return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
+}
-
-bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
+bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
{
{
LOCK(cs_main);
@@ -2511,24 +2654,28 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
}
}
- return ActivateBestChain(state, params);
+ return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
+}
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
+ return g_chainstate.PreciousBlock(state, params, pindex);
}
-bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
+bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
AssertLockHeld(cs_main);
- // Mark the block itself as invalid.
- pindex->nStatus |= BLOCK_FAILED_VALID;
- setDirtyBlockIndex.insert(pindex);
- setBlockIndexCandidates.erase(pindex);
+ // We first disconnect backwards and then mark the blocks as invalid.
+ // This prevents a case where pruned nodes may fail to invalidateblock
+ // and be left unable to start as they have no tip candidates (as there
+ // are no blocks that meet the "have data and are not invalid per
+ // nStatus" criteria for inclusion in setBlockIndexCandidates).
+
+ bool pindex_was_in_chain = false;
+ CBlockIndex *invalid_walk_tip = chainActive.Tip();
DisconnectedBlockTransactions disconnectpool;
while (chainActive.Contains(pindex)) {
- CBlockIndex *pindexWalk = chainActive.Tip();
- pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
- setDirtyBlockIndex.insert(pindexWalk);
- setBlockIndexCandidates.erase(pindexWalk);
+ pindex_was_in_chain = true;
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
if (!DisconnectTip(state, chainparams, &disconnectpool)) {
@@ -2539,6 +2686,21 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
}
}
+ // Now mark the blocks we just disconnected as descendants invalid
+ // (note this may not be all descendants).
+ while (pindex_was_in_chain && invalid_walk_tip != pindex) {
+ invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalid_walk_tip);
+ setBlockIndexCandidates.erase(invalid_walk_tip);
+ invalid_walk_tip = invalid_walk_tip->pprev;
+ }
+
+ // Mark the block itself as invalid.
+ pindex->nStatus |= BLOCK_FAILED_VALID;
+ setDirtyBlockIndex.insert(pindex);
+ setBlockIndexCandidates.erase(pindex);
+ g_failed_blocks.insert(pindex);
+
// DisconnectTip will add transactions to disconnectpool; try to add these
// back to the mempool.
UpdateMempoolForReorg(disconnectpool, true);
@@ -2557,8 +2719,11 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
+bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
+ return g_chainstate.InvalidateBlock(state, chainparams, pindex);
+}
-bool ResetBlockFailureFlags(CBlockIndex *pindex) {
+bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main);
int nHeight = pindex->nHeight;
@@ -2576,6 +2741,7 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr;
}
+ g_failed_blocks.erase(it->second);
}
it++;
}
@@ -2590,8 +2756,11 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
}
return true;
}
+bool ResetBlockFailureFlags(CBlockIndex *pindex) {
+ return g_chainstate.ResetBlockFailureFlags(pindex);
+}
-static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
+CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
{
// Check for duplicate
uint256 hash = block.GetHash();
@@ -2601,7 +2770,6 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block);
- assert(pindexNew);
// We assign the sequence id to blocks only when the full data is available,
// to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage.
@@ -2627,7 +2795,7 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
+bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -2675,7 +2843,7 @@ static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& sta
return true;
}
-static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
+static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
{
LOCK(cs_LastBlockFile);
@@ -2724,7 +2892,7 @@ static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned i
}
}
else
- return state.Error("out of disk space");
+ return error("out of disk space");
}
}
@@ -2899,7 +3067,13 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
/** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO
- * set; UTXO-related validity checks are done in ConnectBlock(). */
+ * set; UTXO-related validity checks are done in ConnectBlock().
+ * NOTE: This function is not currently invoked by ConnectBlock(), so we
+ * should consider upgrade issues if we change which consensus rules are
+ * enforced in this function (eg by adding a new consensus rule). See comment
+ * in ConnectBlock().
+ * Note that -reindex-chainstate skips the validation that happens here!
+ */
static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{
assert(pindexPrev != nullptr);
@@ -2939,6 +3113,12 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
return true;
}
+/** NOTE: This function is not currently invoked by ConnectBlock(), so we
+ * should consider upgrade issues if we change which consensus rules are
+ * enforced in this function (eg by adding a new consensus rule). See comment
+ * in ConnectBlock().
+ * Note that -reindex-chainstate skips the validation that happens here!
+ */
static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
@@ -3020,7 +3200,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
return true;
}
-static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
+bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
{
AssertLockHeld(cs_main);
// Check for duplicate
@@ -3052,6 +3232,21 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+
+ if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
+ for (const CBlockIndex* failedit : g_failed_blocks) {
+ if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
+ assert(failedit->nStatus & BLOCK_FAILED_VALID);
+ CBlockIndex* invalid_walk = pindexPrev;
+ while (invalid_walk != failedit) {
+ invalid_walk->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalid_walk);
+ invalid_walk = invalid_walk->pprev;
+ }
+ return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ }
+ }
+ }
}
if (pindex == nullptr)
pindex = AddToBlockIndex(block);
@@ -3065,13 +3260,15 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
}
// Exposed wrapper for AcceptBlockHeader
-bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)
{
+ if (first_invalid != nullptr) first_invalid->SetNull();
{
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (first_invalid) *first_invalid = header;
return false;
}
if (ppindex) {
@@ -3084,7 +3281,26 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
}
/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
-static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
+static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CChainParams& chainparams, const CDiskBlockPos* dbp) {
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
+ CDiskBlockPos blockPos;
+ if (dbp != nullptr)
+ blockPos = *dbp;
+ if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr)) {
+ error("%s: FindBlockPos failed", __func__);
+ return CDiskBlockPos();
+ }
+ if (dbp == nullptr) {
+ if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) {
+ AbortNode("Failed to write block");
+ return CDiskBlockPos();
+ }
+ }
+ return blockPos;
+}
+
+/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
+bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
{
const CBlock& block = *pblock;
@@ -3101,7 +3317,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
// process an unrequested block if it's new and has enough work to
// advance our tip, and isn't too many blocks ahead.
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
- bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
+ bool fHasMoreOrSameWork = (chainActive.Tip() ? pindex->nChainWork >= chainActive.Tip()->nChainWork : true);
// Blocks that are too out-of-order needlessly limit the effectiveness of
// pruning, because pruning will not delete block files that contain any
// blocks which are too close in height to the tip. Apply this test
@@ -3118,9 +3334,15 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
// and unrequested blocks.
if (fAlreadyHave) return true;
if (!fRequested) { // If we didn't ask for it:
- if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
- if (!fHasMoreWork) return true; // Don't process less-work chains
- if (fTooFarAhead) return true; // Block height is too high
+ if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
+ if (!fHasMoreOrSameWork) return true; // Don't process less-work chains
+ if (fTooFarAhead) return true; // Block height is too high
+
+ // Protect against DoS attacks from low-work chains.
+ // If our tip is behind, a peer could try to send us
+ // low-work blocks on a fake chain that we would never
+ // request; don't process these.
+ if (pindex->nChainWork < nMinimumChainWork) return true;
}
if (fNewBlock) *fNewBlock = true;
@@ -3138,19 +3360,13 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
GetMainSignals().NewPoWValidBlock(pindex, pblock);
- int nHeight = pindex->nHeight;
-
// Write block to history file
try {
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- if (dbp != nullptr)
- blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr))
- return error("AcceptBlock(): FindBlockPos failed");
- if (dbp == nullptr)
- if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
- AbortNode(state, "Failed to write block");
+ CDiskBlockPos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp);
+ if (blockPos.IsNull()) {
+ state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
+ return false;
+ }
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) {
@@ -3160,6 +3376,8 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (fCheckForPruning)
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
+ CheckBlockIndex(chainparams.GetConsensus());
+
return true;
}
@@ -3177,19 +3395,18 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
if (ret) {
// Store to disk
- ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
}
- CheckBlockIndex(chainparams.GetConsensus());
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
- return error("%s: AcceptBlock FAILED", __func__);
+ return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
}
}
NotifyHeaderTip();
CValidationState state; // Only used to report errors, not invalidity - ignore it
- if (!ActivateBestChain(state, chainparams, pblock))
+ if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
return true;
@@ -3199,7 +3416,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{
AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == chainActive.Tip());
- CCoinsViewCache viewNew(pcoinsTip);
+ CCoinsViewCache viewNew(pcoinsTip.get());
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
@@ -3211,7 +3428,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
- if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
+ if (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false;
assert(state.IsValid());
@@ -3223,8 +3440,10 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
*/
/* Calculate the amount of disk space the block & undo files currently use */
-static uint64_t CalculateCurrentUsage()
+uint64_t CalculateCurrentUsage()
{
+ LOCK(cs_LastBlockFile);
+
uint64_t retval = 0;
for (const CBlockFileInfo &file : vinfoBlockFile) {
retval += file.nSize + file.nUndoSize;
@@ -3235,8 +3454,10 @@ static uint64_t CalculateCurrentUsage()
/* Prune a block file (modify associated database entries)*/
void PruneOneBlockFile(const int fileNumber)
{
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) {
- CBlockIndex* pindex = it->second;
+ LOCK(cs_LastBlockFile);
+
+ for (const auto& entry : mapBlockIndex) {
+ CBlockIndex* pindex = entry.second;
if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
pindex->nStatus &= ~BLOCK_HAVE_UNDO;
@@ -3384,7 +3605,7 @@ static FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fRe
return nullptr;
fs::path path = GetBlockPosFilename(pos, prefix);
fs::create_directories(path.parent_path());
- FILE* file = fsbridge::fopen(path, "rb+");
+ FILE* file = fsbridge::fopen(path, fReadOnly ? "rb": "rb+");
if (!file && !fReadOnly)
file = fsbridge::fopen(path, "wb+");
if (!file) {
@@ -3415,7 +3636,7 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
}
-CBlockIndex * InsertBlockIndex(uint256 hash)
+CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
{
if (hash.IsNull())
return nullptr;
@@ -3427,17 +3648,15 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
- if (!pindexNew)
- throw std::runtime_error(std::string(__func__) + ": new CBlockIndex failed");
mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
}
-bool static LoadBlockIndexDB(const CChainParams& chainparams)
+bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree)
{
- if (!pblocktree->LoadBlockIndexGuts(chainparams.GetConsensus(), InsertBlockIndex))
+ if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash){ return this->InsertBlockIndex(hash); }))
return false;
boost::this_thread::interruption_point();
@@ -3470,6 +3689,10 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindex->nChainTx = pindex->nTx;
}
}
+ if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) {
+ pindex->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(pindex);
+ }
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == nullptr))
setBlockIndexCandidates.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
@@ -3480,6 +3703,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindexBestHeader = pindex;
}
+ return true;
+}
+
+bool static LoadBlockIndexDB(const CChainParams& chainparams)
+{
+ if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
+ return false;
+
// Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile);
vinfoBlockFile.resize(nLastBlockFile + 1);
@@ -3523,7 +3754,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
// Check whether we need to continue reindexing
bool fReindexing = false;
pblocktree->ReadReindexing(fReindexing);
- fReindex |= fReindexing;
+ if(fReindexing) fReindex = true;
// Check whether we have a transaction index
pblocktree->ReadFlag("txindex", fTxIndex);
@@ -3552,7 +3783,7 @@ bool LoadChainTip(const CChainParams& chainparams)
return false;
chainActive.SetTip(it->second);
- PruneBlockIndexCandidates();
+ g_chainstate.PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
@@ -3563,12 +3794,12 @@ bool LoadChainTip(const CChainParams& chainparams)
CVerifyDB::CVerifyDB()
{
- uiInterface.ShowProgress(_("Verifying blocks..."), 0);
+ uiInterface.ShowProgress(_("Verifying blocks..."), 0, false);
}
CVerifyDB::~CVerifyDB()
{
- uiInterface.ShowProgress("", 100);
+ uiInterface.ShowProgress("", 100, false);
}
bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)
@@ -3598,7 +3829,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
LogPrintf("[%d%%]...", percentageDone);
reportDone = percentageDone/10;
}
- uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone);
+ uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
@@ -3617,16 +3848,16 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo;
- CDiskBlockPos pos = pindex->GetUndoPos();
- if (!pos.IsNull()) {
- if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash()))
+ if (!pindex->GetUndoPos().IsNull()) {
+ if (!UndoReadFromDisk(undo, pindex)) {
return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ }
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
- DisconnectResult res = DisconnectBlock(block, pindex, coins);
+ DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -3649,12 +3880,12 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlockIndex *pindex = pindexState;
while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
- uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))));
+ uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false);
pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
- if (!ConnectBlock(block, state, pindex, coins, chainparams))
+ if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
}
@@ -3666,7 +3897,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
-static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
+bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
{
// TODO: merge with ConnectBlock
CBlock block;
@@ -3686,7 +3917,7 @@ static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs,
return true;
}
-bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
+bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
{
LOCK(cs_main);
@@ -3696,7 +3927,7 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
if (hashHeads.empty()) return true; // We're already in a consistent state.
if (hashHeads.size() != 2) return error("ReplayBlocks(): unknown inconsistent state");
- uiInterface.ShowProgress(_("Replaying blocks..."), 0);
+ uiInterface.ShowProgress(_("Replaying blocks..."), 0, false);
LogPrintf("Replaying blocks\n");
const CBlockIndex* pindexOld = nullptr; // Old tip during the interrupted flush.
@@ -3747,11 +3978,15 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
cache.SetBestBlock(pindexNew->GetBlockHash());
cache.Flush();
- uiInterface.ShowProgress("", 100);
+ uiInterface.ShowProgress("", 100, false);
return true;
}
-bool RewindBlockIndex(const CChainParams& params)
+bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
+ return g_chainstate.ReplayBlocks(params, view);
+}
+
+bool CChainState::RewindBlockIndex(const CChainParams& params)
{
LOCK(cs_main);
@@ -3788,8 +4023,8 @@ bool RewindBlockIndex(const CChainParams& params)
// Reduce validity flag and have-data flags.
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
- CBlockIndex* pindexIter = it->second;
+ for (const auto& entry : mapBlockIndex) {
+ CBlockIndex* pindexIter = entry.second;
// Note: If we encounter an insufficiently validated block that
// is on chainActive, it must be because we are a pruning node, and
@@ -3832,10 +4067,21 @@ bool RewindBlockIndex(const CChainParams& params)
PruneBlockIndexCandidates();
CheckBlockIndex(params.GetConsensus());
+ }
+
+ return true;
+}
+bool RewindBlockIndex(const CChainParams& params) {
+ if (!g_chainstate.RewindBlockIndex(params)) {
+ return false;
+ }
+
+ if (chainActive.Tip() != nullptr) {
// FlushStateToDisk can possibly read chainActive. Be conservative
// and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon.
+ CValidationState state;
if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {
return false;
}
@@ -3844,13 +4090,18 @@ bool RewindBlockIndex(const CChainParams& params)
return true;
}
+void CChainState::UnloadBlockIndex() {
+ nBlockSequenceId = 1;
+ g_failed_blocks.clear();
+ setBlockIndexCandidates.clear();
+}
+
// May NOT be used after any connections are up as much
// of the peer-processing logic assumes a consistent
// block index state
void UnloadBlockIndex()
{
LOCK(cs_main);
- setBlockIndexCandidates.clear();
chainActive.SetTip(nullptr);
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
@@ -3858,7 +4109,6 @@ void UnloadBlockIndex()
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
- nBlockSequenceId = 1;
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
versionbitscache.Clear();
@@ -3871,6 +4121,8 @@ void UnloadBlockIndex()
}
mapBlockIndex.clear();
fHavePruned = false;
+
+ g_chainstate.UnloadBlockIndex();
}
bool LoadBlockIndex(const CChainParams& chainparams)
@@ -3898,7 +4150,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
return true;
}
-bool LoadGenesisBlock(const CChainParams& chainparams)
+bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
{
LOCK(cs_main);
@@ -3911,15 +4163,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
try {
CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
- // Start new block file
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- CValidationState state;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
- return error("%s: FindBlockPos failed", __func__);
- if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
+ CDiskBlockPos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr);
+ if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed", __func__);
CBlockIndex *pindex = AddToBlockIndex(block);
+ CValidationState state;
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("%s: genesis block not accepted", __func__);
} catch (const std::runtime_error& e) {
@@ -3929,6 +4177,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
return true;
}
+bool LoadGenesisBlock(const CChainParams& chainparams)
+{
+ return g_chainstate.LoadGenesisBlock(chainparams);
+}
+
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp)
{
// Map of disk positions for blocks with unknown parent (only used for reindex)
@@ -3989,7 +4242,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main);
CValidationState state;
- if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
+ if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
nLoaded++;
if (state.IsError())
break;
@@ -4023,7 +4276,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
head.ToString());
LOCK(cs_main);
CValidationState dummy;
- if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
+ if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
@@ -4046,7 +4299,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
return nLoaded > 0;
}
-void static CheckBlockIndex(const Consensus::Params& consensusParams)
+void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
{
if (!fCheckBlockIndex) {
return;
@@ -4064,8 +4317,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
// Build forward-pointing map of the entire block tree.
std::multimap<CBlockIndex*,CBlockIndex*> forward;
- for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
- forward.insert(std::make_pair(it->second->pprev, it->second));
+ for (auto& entry : mapBlockIndex) {
+ forward.insert(std::make_pair(entry.second->pprev, entry.second));
}
assert(forward.size() == mapBlockIndex.size());
@@ -4237,6 +4490,8 @@ std::string CBlockFileInfo::ToString() const
CBlockFileInfo* GetBlockFileInfo(size_t n)
{
+ LOCK(cs_LastBlockFile);
+
return &vinfoBlockFile.at(n);
}
@@ -4272,8 +4527,9 @@ bool LoadMempool(void)
}
int64_t count = 0;
- int64_t skipped = 0;
+ int64_t expired = 0;
int64_t failed = 0;
+ int64_t already_there = 0;
int64_t nNow = GetTime();
try {
@@ -4299,14 +4555,23 @@ bool LoadMempool(void)
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
- AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, true, nullptr, nTime, nullptr, false, 0);
+ AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, nullptr /* pfMissingInputs */, nTime,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */);
if (state.IsValid()) {
++count;
} else {
- ++failed;
+ // mempool may contain the transaction already, e.g. from
+ // wallet(s) having loaded it while we were processing
+ // mempool transactions; consider these as valid, instead of
+ // failed, but mark them as 'already there'
+ if (mempool.exists(tx->GetHash())) {
+ ++already_there;
+ } else {
+ ++failed;
+ }
}
} else {
- ++skipped;
+ ++expired;
}
if (ShutdownRequested())
return false;
@@ -4322,11 +4587,11 @@ bool LoadMempool(void)
return false;
}
- LogPrintf("Imported mempool transactions from disk: %i successes, %i failed, %i expired\n", count, failed, skipped);
+ LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there\n", count, failed, expired, already_there);
return true;
}
-void DumpMempool(void)
+bool DumpMempool(void)
{
int64_t start = GetTimeMicros();
@@ -4346,7 +4611,7 @@ void DumpMempool(void)
try {
FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
if (!filestr) {
- return;
+ return false;
}
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
@@ -4367,14 +4632,16 @@ void DumpMempool(void)
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
- LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*0.000001, (last-mid)*0.000001);
+ LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO);
} catch (const std::exception& e) {
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ return false;
}
+ return true;
}
//! Guess how far we are in the verification process at the given block index
-double GuessVerificationProgress(const ChainTxData& data, CBlockIndex *pindex) {
+double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) {
if (pindex == nullptr)
return 0.0;
diff --git a/src/validation.h b/src/validation.h
index edb8eab894..4c8e041af0 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -7,17 +7,17 @@
#define BITCOIN_VALIDATION_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "amount.h"
-#include "coins.h"
-#include "fs.h"
-#include "protocol.h" // For CMessageHeader::MessageStartChars
-#include "policy/feerate.h"
-#include "script/script_error.h"
-#include "sync.h"
-#include "versionbits.h"
+#include <amount.h>
+#include <coins.h>
+#include <fs.h>
+#include <protocol.h> // For CMessageHeader::MessageStartChars
+#include <policy/feerate.h>
+#include <script/script_error.h>
+#include <sync.h>
+#include <versionbits.h>
#include <algorithm>
#include <exception>
@@ -45,9 +45,9 @@ struct ChainTxData;
struct PrecomputedTransactionData;
struct LockPoints;
-/** Default for DEFAULT_WHITELISTRELAY. */
+/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
-/** Default for DEFAULT_WHITELISTFORCERELAY. */
+/** Default for -whitelistforcerelay. */
static const bool DEFAULT_WHITELISTFORCERELAY = true;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
@@ -94,8 +94,8 @@ static const int MAX_CMPCTBLOCK_DEPTH = 5;
static const int MAX_BLOCKTXN_DEPTH = 10;
/** Size of the "block download window": how far ahead of our current height do we fetch?
* Larger windows tolerate larger download speed differences between peer, but increase the potential
- * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
- * harder). We'll probably want to make this a per-peer adaptive value at some point. */
+ * degree of disordering of blocks on disk (which make reindexing and pruning harder). We'll probably
+ * want to make this a per-peer adaptive value at some point. */
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blocks/block index to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
@@ -159,15 +159,14 @@ extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
-extern BlockMap mapBlockIndex;
+extern BlockMap& mapBlockIndex;
extern uint64_t nLastBlockTx;
-extern uint64_t nLastBlockSize;
extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
extern std::atomic_bool fImporting;
-extern bool fReindex;
+extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
@@ -186,6 +185,9 @@ extern bool fEnableReplacement;
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
extern uint256 hashAssumeValid;
+/** Minimum work we will assume exists on some valid chain. */
+extern arith_uint256 nMinimumChainWork;
+
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -201,6 +203,8 @@ extern bool fPruneMode;
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
+/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
+static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
@@ -245,8 +249,9 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
* @param[out] state This may be set to an Error state if any error occurred processing them
* @param[in] chainparams The params for the chain we want to connect to
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
+ * @param[out] first_invalid First header that fails validation, if one exists
*/
-bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr);
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr, CBlockHeader *first_invalid=nullptr);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
@@ -270,13 +275,16 @@ void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
-bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
+bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr);
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
-double GuessVerificationProgress(const ChainTxData& data, CBlockIndex* pindex);
+double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
+
+/** Calculate the amount of disk space the block & undo files currently use */
+uint64_t CalculateCurrentUsage();
/**
* Mark one block file as pruned.
@@ -288,8 +296,6 @@ void PruneOneBlockFile(const int fileNumber);
*/
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
-/** Create a new block index entry for a given block hash */
-CBlockIndex * InsertBlockIndex(uint256 hash);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
@@ -299,9 +305,9 @@ void PruneBlockFilesManual(int nManualPruneHeight);
/** (try to) add transaction to memory pool
* plTxnReplaced will be appended to with all transactions replaced from mempool **/
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
- bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced = nullptr,
- bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
+ bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
+ bool bypass_limits, const CAmount nAbsurdFee);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -355,8 +361,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = null
class CScriptCheck
{
private:
- CScript scriptPubKey;
- CAmount amount;
+ CTxOut m_tx_out;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
@@ -365,17 +370,15 @@ private:
PrecomputedTransactionData *txdata;
public:
- CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
- CScriptCheck(const CScript& scriptPubKeyIn, const CAmount amountIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
- scriptPubKey(scriptPubKeyIn), amount(amountIn),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
+ CScriptCheck(): ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
+ CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
+ m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
void swap(CScriptCheck &check) {
- scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
- std::swap(amount, check.amount);
+ std::swap(m_tx_out, check.m_tx_out);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
@@ -438,16 +441,16 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
-extern CChain chainActive;
+extern CChain& chainActive;
/** Global variable that points to the coins database (protected by cs_main) */
-extern CCoinsViewDB *pcoinsdbview;
+extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
-extern CCoinsViewCache *pcoinsTip;
+extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
-extern CBlockTreeDB *pblocktree;
+extern std::unique_ptr<CBlockTreeDB> pblocktree;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
@@ -475,7 +478,7 @@ static const unsigned int REJECT_HIGHFEE = 0x100;
CBlockFileInfo* GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
-void DumpMempool();
+bool DumpMempool();
/** Load the mempool from disk. */
bool LoadMempool();
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index bf20d606f8..abbd8cc4d2 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -3,11 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "validationinterface.h"
-#include "init.h"
-#include "scheduler.h"
-#include "sync.h"
-#include "util.h"
+#include <validationinterface.h>
+
+#include <init.h>
+#include <primitives/block.h>
+#include <scheduler.h>
+#include <sync.h>
+#include <txmempool.h>
+#include <util.h>
#include <list>
#include <atomic>
@@ -19,6 +22,7 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
+ boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
boost::signals2::signal<void (const uint256 &)> Inventory;
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
@@ -30,7 +34,7 @@ struct MainSignalsInstance {
// our own queue here :(
SingleThreadedSchedulerClient m_schedulerClient;
- MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
+ explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
};
static CMainSignals g_signals;
@@ -45,7 +49,17 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() {
}
void CMainSignals::FlushBackgroundCallbacks() {
- m_internals->m_schedulerClient.EmptyQueue();
+ if (m_internals) {
+ m_internals->m_schedulerClient.EmptyQueue();
+ }
+}
+
+void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
+ pool.NotifyEntryRemoved.connect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
+}
+
+void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) {
+ pool.NotifyEntryRemoved.disconnect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
}
CMainSignals& GetMainSignals()
@@ -58,6 +72,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
@@ -73,11 +88,15 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->TransactionRemovedFromMempool.disconnect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
void UnregisterAllValidationInterfaces() {
+ if (!g_signals.m_internals) {
+ return;
+ }
g_signals.m_internals->BlockChecked.disconnect_all_slots();
g_signals.m_internals->Broadcast.disconnect_all_slots();
g_signals.m_internals->Inventory.disconnect_all_slots();
@@ -85,32 +104,57 @@ void UnregisterAllValidationInterfaces() {
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
g_signals.m_internals->BlockConnected.disconnect_all_slots();
g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
+ g_signals.m_internals->TransactionRemovedFromMempool.disconnect_all_slots();
g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots();
g_signals.m_internals->NewPoWValidBlock.disconnect_all_slots();
}
+void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
+ g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
+}
+
+void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason reason) {
+ if (reason != MemPoolRemovalReason::BLOCK && reason != MemPoolRemovalReason::CONFLICT) {
+ m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
+ m_internals->TransactionRemovedFromMempool(ptx);
+ });
+ }
+}
+
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
- m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+ m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
+ m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+ });
}
void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
- m_internals->TransactionAddedToMempool(ptx);
+ m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
+ m_internals->TransactionAddedToMempool(ptx);
+ });
}
-void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
- m_internals->BlockConnected(pblock, pindex, vtxConflicted);
+void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>>& pvtxConflicted) {
+ m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, pvtxConflicted, this] {
+ m_internals->BlockConnected(pblock, pindex, *pvtxConflicted);
+ });
}
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) {
- m_internals->BlockDisconnected(pblock);
+ m_internals->m_schedulerClient.AddToProcessQueue([pblock, this] {
+ m_internals->BlockDisconnected(pblock);
+ });
}
void CMainSignals::SetBestChain(const CBlockLocator &locator) {
- m_internals->SetBestChain(locator);
+ m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
+ m_internals->SetBestChain(locator);
+ });
}
void CMainSignals::Inventory(const uint256 &hash) {
- m_internals->Inventory(hash);
+ m_internals->m_schedulerClient.AddToProcessQueue([hash, this] {
+ m_internals->Inventory(hash);
+ });
}
void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index d6da2bc1fd..7b5d138414 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -6,9 +6,10 @@
#ifndef BITCOIN_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
-#include <memory>
+#include <primitives/transaction.h> // CTransaction(Ref)
-#include "primitives/transaction.h" // CTransaction(Ref)
+#include <functional>
+#include <memory>
class CBlock;
class CBlockIndex;
@@ -20,6 +21,8 @@ class CValidationInterface;
class CValidationState;
class uint256;
class CScheduler;
+class CTxMemPool;
+enum class MemPoolRemovalReason;
// These functions dispatch to one or all registered wallets
@@ -29,23 +32,66 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn);
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllValidationInterfaces();
+/**
+ * Pushes a function to callback onto the notification queue, guaranteeing any
+ * callbacks generated prior to now are finished when the function is called.
+ *
+ * Be very careful blocking on func to be called if any locks are held -
+ * validation interface clients may not be able to make progress as they often
+ * wait for things like cs_main, so blocking until func is called with cs_main
+ * will result in a deadlock (that DEBUG_LOCKORDER will miss).
+ */
+void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
class CValidationInterface {
protected:
- /** Notifies listeners of updated block chain tip */
+ /**
+ * Notifies listeners of updated block chain tip
+ *
+ * Called on a background thread.
+ */
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
- /** Notifies listeners of a transaction having been added to mempool. */
+ /**
+ * Notifies listeners of a transaction having been added to mempool.
+ *
+ * Called on a background thread.
+ */
virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
/**
+ * Notifies listeners of a transaction leaving mempool.
+ *
+ * This only fires for transactions which leave mempool because of expiry,
+ * size limiting, reorg (changes in lock times/coinbase maturity), or
+ * replacement. This does not include any transactions which are included
+ * in BlockConnectedDisconnected either in block->vtx or in txnConflicted.
+ *
+ * Called on a background thread.
+ */
+ virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx) {}
+ /**
* Notifies listeners of a block being connected.
* Provides a vector of transactions evicted from the mempool as a result.
+ *
+ * Called on a background thread.
*/
virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
- /** Notifies listeners of a block being disconnected */
+ /**
+ * Notifies listeners of a block being disconnected
+ *
+ * Called on a background thread.
+ */
virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
- /** Notifies listeners of the new active block chain on-disk. */
+ /**
+ * Notifies listeners of the new active block chain on-disk.
+ *
+ * Called on a background thread.
+ */
virtual void SetBestChain(const CBlockLocator &locator) {}
- /** Notifies listeners about an inventory item being seen on the network. */
+ /**
+ * Notifies listeners about an inventory item being seen on the network.
+ *
+ * Called on a background thread.
+ */
virtual void Inventory(const uint256 &hash) {}
/** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
@@ -73,6 +119,9 @@ private:
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
+ friend void ::CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
+
+ void MempoolEntryRemoved(CTransactionRef tx, MemPoolRemovalReason reason);
public:
/** Register a CScheduler to give callbacks which should run in the background (may only be called once) */
@@ -82,9 +131,14 @@ public:
/** Call any remaining callbacks on the calling thread */
void FlushBackgroundCallbacks();
+ /** Register with mempool to call TransactionRemovedFromMempool callbacks */
+ void RegisterWithMempoolSignals(CTxMemPool& pool);
+ /** Unregister with mempool */
+ void UnregisterWithMempoolSignals(CTxMemPool& pool);
+
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
void TransactionAddedToMempool(const CTransactionRef &);
- void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &);
+ void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
void SetBestChain(const CBlockLocator &);
void Inventory(const uint256 &);
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 04a692d826..3bd00ccb23 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "versionbits.h"
-#include "consensus/params.h"
+#include <versionbits.h>
+#include <consensus/params.h>
const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
@@ -27,6 +27,11 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
int64_t nTimeStart = BeginTime(params);
int64_t nTimeTimeout = EndTime(params);
+ // Check if this deployment is always active.
+ if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
+ return THRESHOLD_ACTIVE;
+ }
+
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
if (pindexPrev != nullptr) {
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
@@ -107,7 +112,7 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
// return the numerical statistics of blocks signalling the specified BIP9 condition in this current period
BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const
{
- BIP9Stats stats;
+ BIP9Stats stats = {};
stats.period = Period(params);
stats.threshold = Threshold(params);
@@ -136,6 +141,11 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{
+ int64_t start_time = BeginTime(params);
+ if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
+ return 0;
+ }
+
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
@@ -185,7 +195,7 @@ protected:
}
public:
- VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
+ explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
};
diff --git a/src/versionbits.h b/src/versionbits.h
index 71dc0c8500..0e111ed7a1 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CONSENSUS_VERSIONBITS
#define BITCOIN_CONSENSUS_VERSIONBITS
-#include "chain.h"
+#include <chain.h>
#include <map>
/** What block version to use for new blocks (pre versionbits) */
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index fc0e7c519e..15fd105779 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_WALLET_COINCONTROL_H
#define BITCOIN_WALLET_COINCONTROL_H
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "primitives/transaction.h"
-#include "wallet/wallet.h"
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <primitives/transaction.h>
+#include <wallet/wallet.h>
#include <boost/optional.hpp>
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index dcce88cedc..4cd7db048b 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypter.h"
+#include <wallet/crypter.h>
-#include "crypto/aes.h"
-#include "crypto/sha512.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
+#include <crypto/aes.h>
+#include <crypto/sha512.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
#include <string>
#include <vector>
@@ -27,8 +27,7 @@ int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, cons
CSHA512 di;
di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
- if(chSalt.size())
- di.Write(&chSalt[0], chSalt.size());
+ di.Write(chSalt.data(), chSalt.size());
di.Finalize(buf);
for(int i = 0; i != count - 1; i++)
@@ -82,7 +81,7 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned
vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
- size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), &vchCiphertext[0]);
+ size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
if(nLen < vchPlaintext.size())
return false;
vchCiphertext.resize(nLen);
@@ -101,7 +100,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
vchPlaintext.resize(nLen);
AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
- nLen = dec.Decrypt(&vchCiphertext[0], vchCiphertext.size(), &vchPlaintext[0]);
+ nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
if(nLen == 0)
return false;
vchPlaintext.resize(nLen);
@@ -113,7 +112,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
+ memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
@@ -123,7 +122,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
+ memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
@@ -153,6 +152,15 @@ bool CCryptoKeyStore::SetCrypted()
return true;
}
+bool CCryptoKeyStore::IsLocked() const
+{
+ if (!IsCrypted()) {
+ return false;
+ }
+ LOCK(cs_KeyStore);
+ return vMasterKey.empty();
+}
+
bool CCryptoKeyStore::Lock()
{
if (!SetCrypted())
@@ -207,21 +215,23 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+ }
- if (IsLocked())
- return false;
+ if (IsLocked()) {
+ return false;
+ }
- std::vector<unsigned char> vchCryptedSecret;
- CKeyingMaterial vchSecret(key.begin(), key.end());
- if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
- return false;
+ std::vector<unsigned char> vchCryptedSecret;
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
+ return false;
+ }
- if (!AddCryptedKey(pubkey, vchCryptedSecret))
- return false;
+ if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
+ return false;
}
return true;
}
@@ -229,72 +239,88 @@ bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
- {
- LOCK(cs_KeyStore);
- if (!SetCrypted())
- return false;
-
- mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
+ LOCK(cs_KeyStore);
+ if (!SetCrypted()) {
+ return false;
}
+
+ mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
return true;
}
+bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::HaveKey(address);
+ }
+ return mapCryptedKeys.count(address) > 0;
+}
+
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetKey(address, keyOut);
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::GetKey(address, keyOut);
+ }
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
- }
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
{
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+ vchPubKeyOut = (*mi).second.first;
+ return true;
+ }
+ // Check for watch-only pubkeys
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+}
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- vchPubKeyOut = (*mi).second.first;
- return true;
- }
- // Check for watch-only pubkeys
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+std::set<CKeyID> CCryptoKeyStore::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::GetKeys();
}
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapCryptedKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
+ LOCK(cs_KeyStore);
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ for (KeyMap::value_type& mKey : mapKeys)
{
- LOCK(cs_KeyStore);
- if (!mapCryptedKeys.empty() || IsCrypted())
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
-
- fUseCrypto = true;
- for (KeyMap::value_type& mKey : mapKeys)
- {
- const CKey &key = mKey.second;
- CPubKey vchPubKey = key.GetPubKey();
- CKeyingMaterial vchSecret(key.begin(), key.end());
- std::vector<unsigned char> vchCryptedSecret;
- if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
- return false;
- if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
- return false;
- }
- mapKeys.clear();
}
+ mapKeys.clear();
return true;
}
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 1dc44e424f..7b0936ba0d 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -5,9 +5,11 @@
#ifndef BITCOIN_WALLET_CRYPTER_H
#define BITCOIN_WALLET_CRYPTER_H
-#include "keystore.h"
-#include "serialize.h"
-#include "support/allocators/secure.h"
+#include <keystore.h>
+#include <serialize.h>
+#include <support/allocators/secure.h>
+
+#include <atomic>
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
@@ -16,13 +18,13 @@ const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
/**
* Private key encryption is done based on a CMasterKey,
* which holds a salt and random encryption key.
- *
+ *
* CMasterKeys are encrypted using AES-256-CBC using a key
* derived using derivation method nDerivationMethod
* (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
* vchOtherDerivationParameters is provided for alternative algorithms
* which may require more parameters (such as scrypt).
- *
+ *
* Wallet Private Keys are then encrypted using AES-256-CBC
* with the double-sha256 of the public key as the IV, and the
* master key's key as the encryption key (see keystore.[ch]).
@@ -113,13 +115,12 @@ public:
class CCryptoKeyStore : public CBasicKeyStore
{
private:
- CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey;
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
- bool fUseCrypto;
+ std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
@@ -131,60 +132,23 @@ protected:
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+ CryptedKeyMap mapCryptedKeys;
public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
{
}
- bool IsCrypted() const
- {
- return fUseCrypto;
- }
-
- bool IsLocked() const
- {
- if (!IsCrypted())
- return false;
- bool result;
- {
- LOCK(cs_KeyStore);
- result = vMasterKey.empty();
- }
- return result;
- }
-
+ bool IsCrypted() const { return fUseCrypto; }
+ bool IsLocked() const;
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
- bool HaveKey(const CKeyID &address) const override
- {
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::HaveKey(address);
- return mapCryptedKeys.count(address) > 0;
- }
- return false;
- }
+ bool HaveKey(const CKeyID &address) const override;
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- void GetKeys(std::set<CKeyID> &setAddress) const override
- {
- if (!IsCrypted())
- {
- CBasicKeyStore::GetKeys(setAddress);
- return;
- }
- setAddress.clear();
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
- while (mi != mapCryptedKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
- }
- }
+ std::set<CKeyID> GetKeys() const override;
/**
* Wallet status (encrypted, locked) changed.
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index b12d46e40a..d4cd30dfac 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "db.h"
+#include <wallet/db.h>
-#include "addrman.h"
-#include "fs.h"
-#include "hash.h"
-#include "protocol.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <addrman.h>
+#include <hash.h>
+#include <protocol.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <wallet/walletutil.h>
#include <stdint.h>
@@ -20,6 +20,40 @@
#include <boost/thread.hpp>
+namespace {
+//! Make sure database has a unique fileid within the environment. If it
+//! doesn't, throw an error. BDB caches do not work properly when more than one
+//! open database has the same fileid (values written to one database may show
+//! up in reads to other databases).
+//!
+//! BerkeleyDB generates unique fileids by default
+//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
+//! so bitcoin should never create different databases with the same fileid, but
+//! this error can be triggered if users manually copy database files.
+void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
+{
+ if (env.IsMock()) return;
+
+ u_int8_t fileid[DB_FILE_ID_LEN];
+ int ret = db.get_mpf()->get_fileid(fileid);
+ if (ret != 0) {
+ throw std::runtime_error(strprintf("CDB: Can't open database %s (get_fileid failed with %d)", filename, ret));
+ }
+
+ for (const auto& item : env.mapDb) {
+ u_int8_t item_fileid[DB_FILE_ID_LEN];
+ if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 &&
+ memcmp(fileid, item_fileid, sizeof(fileid)) == 0) {
+ const char* item_filename = nullptr;
+ item.second->get_dbname(&item_filename, nullptr);
+ throw std::runtime_error(strprintf("CDB: Can't open database %s (duplicates fileid %s from %s)", filename,
+ HexStr(std::begin(item_fileid), std::end(item_fileid)),
+ item_filename ? item_filename : "(unknown database)"));
+ }
+ }
+}
+} // namespace
+
//
// CDB
//
@@ -41,13 +75,12 @@ void CDBEnv::EnvShutdown()
void CDBEnv::Reset()
{
- delete dbenv;
- dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
+ dbenv.reset(new DbEnv(DB_CXX_NO_EXCEPTIONS));
fDbEnvInit = false;
fMockDb = false;
}
-CDBEnv::CDBEnv() : dbenv(nullptr)
+CDBEnv::CDBEnv()
{
Reset();
}
@@ -55,8 +88,6 @@ CDBEnv::CDBEnv() : dbenv(nullptr)
CDBEnv::~CDBEnv()
{
EnvShutdown();
- delete dbenv;
- dbenv = nullptr;
}
void CDBEnv::Close()
@@ -101,8 +132,10 @@ bool CDBEnv::Open(const fs::path& pathIn)
DB_RECOVER |
nEnvFlags,
S_IRUSR | S_IWUSR);
- if (ret != 0)
+ if (ret != 0) {
+ dbenv->close(0);
return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
+ }
fDbEnvInit = true;
fMockDb = false;
@@ -146,7 +179,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
- Db db(dbenv, 0);
+ Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result == 0)
return VERIFY_OK;
@@ -189,16 +222,16 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0));
+ std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(bitdb.dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
DB_BTREE, // Database type
DB_CREATE, // Flags
0);
- if (ret > 0)
- {
+ if (ret > 0) {
LogPrintf("Cannot create database file %s\n", filename);
+ pdbCopy->close(0);
return false;
}
@@ -224,7 +257,7 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
return fSuccess;
}
-bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
+bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walletDir, std::string& errorStr)
{
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
LogPrintf("Using wallet %s\n", walletFile);
@@ -232,15 +265,15 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataD
// Wallet file must be a plain filename without a directory
if (walletFile != fs::basename(walletFile) + fs::extension(walletFile))
{
- errorStr = strprintf(_("Wallet %s resides outside data directory %s"), walletFile, dataDir.string());
+ errorStr = strprintf(_("Wallet %s resides outside wallet directory %s"), walletFile, walletDir.string());
return false;
}
- if (!bitdb.Open(dataDir))
+ if (!bitdb.Open(walletDir))
{
// try moving the database env out of the way
- fs::path pathDatabase = dataDir / "database";
- fs::path pathDatabaseBak = dataDir / strprintf("database.%d.bak", GetTime());
+ fs::path pathDatabase = walletDir / "database";
+ fs::path pathDatabaseBak = walletDir / strprintf("database.%d.bak", GetTime());
try {
fs::rename(pathDatabase, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
@@ -249,18 +282,18 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataD
}
// try again
- if (!bitdb.Open(dataDir)) {
+ if (!bitdb.Open(walletDir)) {
// if it still fails, it probably means we can't even create the database env
- errorStr = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir());
+ errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
return false;
}
}
return true;
}
-bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)
+bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& walletDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)
{
- if (fs::exists(dataDir / walletFile))
+ if (fs::exists(walletDir / walletFile))
{
std::string backup_filename;
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc, backup_filename);
@@ -270,7 +303,7 @@ bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& data
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."),
- walletFile, backup_filename, dataDir);
+ walletFile, backup_filename, walletDir);
}
if (r == CDBEnv::RECOVER_FAIL)
{
@@ -298,7 +331,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
std::stringstream strDump;
- Db db(dbenv, 0);
+ Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, &strDump, flags);
if (result == DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
@@ -374,38 +407,37 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
{
LOCK(env->cs_db);
- if (!env->Open(GetDataDir()))
+ if (!env->Open(GetWalletDir()))
throw std::runtime_error("CDB: Failed to open database environment.");
- strFile = strFilename;
- ++env->mapFileUseCount[strFile];
- pdb = env->mapDb[strFile];
+ pdb = env->mapDb[strFilename];
if (pdb == nullptr) {
int ret;
- pdb = new Db(env->dbenv, 0);
+ std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0);
bool fMockDb = env->IsMock();
if (fMockDb) {
- DbMpoolFile* mpf = pdb->get_mpf();
+ DbMpoolFile* mpf = pdb_temp->get_mpf();
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
- if (ret != 0)
- throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
+ if (ret != 0) {
+ throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFilename));
+ }
}
- ret = pdb->open(nullptr, // Txn pointer
- fMockDb ? nullptr : strFile.c_str(), // Filename
- fMockDb ? strFile.c_str() : "main", // Logical db name
- DB_BTREE, // Database type
- nFlags, // Flags
+ ret = pdb_temp->open(nullptr, // Txn pointer
+ fMockDb ? nullptr : strFilename.c_str(), // Filename
+ fMockDb ? strFilename.c_str() : "main", // Logical db name
+ DB_BTREE, // Database type
+ nFlags, // Flags
0);
if (ret != 0) {
- delete pdb;
- pdb = nullptr;
- --env->mapFileUseCount[strFile];
- strFile = "";
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
+ CheckUniqueFileid(*env, strFilename, *pdb_temp);
+
+ pdb = pdb_temp.release();
+ env->mapDb[strFilename] = pdb;
if (fCreate && !Exists(std::string("version"))) {
bool fTmp = fReadOnly;
@@ -413,9 +445,9 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
WriteVersion(CLIENT_VERSION);
fReadOnly = fTmp;
}
-
- env->mapDb[strFile] = pdb;
}
+ ++env->mapFileUseCount[strFilename];
+ strFile = strFilename;
}
}
@@ -490,7 +522,7 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(dbw, "r");
- Db* pdbCopy = new Db(env->dbenv, 0);
+ std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
strFileRes.c_str(), // Filename
@@ -536,14 +568,15 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
env->CloseDb(strFile);
if (pdbCopy->close(0))
fSuccess = false;
- delete pdbCopy;
+ } else {
+ pdbCopy->close(0);
}
}
if (fSuccess) {
- Db dbA(env->dbenv, 0);
+ Db dbA(env->dbenv.get(), 0);
if (dbA.remove(strFile.c_str(), nullptr, 0))
fSuccess = false;
- Db dbB(env->dbenv, 0);
+ Db dbB(env->dbenv.get(), 0);
if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0))
fSuccess = false;
}
@@ -554,7 +587,6 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
}
MilliSleep(100);
}
- return false;
}
@@ -663,12 +695,17 @@ bool CWalletDBWrapper::Backup(const std::string& strDest)
env->mapFileUseCount.erase(strFile);
// Copy wallet file
- fs::path pathSrc = GetDataDir() / strFile;
+ fs::path pathSrc = GetWalletDir() / strFile;
fs::path pathDest(strDest);
if (fs::is_directory(pathDest))
pathDest /= strFile;
try {
+ if (fs::equivalent(pathSrc, pathDest)) {
+ LogPrintf("cannot backup to wallet source file %s\n", pathDest.string());
+ return false;
+ }
+
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
LogPrintf("copied %s to %s\n", strFile, pathDest.string());
return true;
@@ -680,7 +717,6 @@ bool CWalletDBWrapper::Backup(const std::string& strDest)
}
MilliSleep(100);
}
- return false;
}
void CWalletDBWrapper::Flush(bool shutdown)
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 3614e34fbb..ed2ee65cac 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_WALLET_DB_H
#define BITCOIN_WALLET_DB_H
-#include "clientversion.h"
-#include "fs.h"
-#include "serialize.h"
-#include "streams.h"
-#include "sync.h"
-#include "version.h"
+#include <clientversion.h>
+#include <fs.h>
+#include <serialize.h>
+#include <streams.h>
+#include <sync.h>
+#include <version.h>
#include <atomic>
#include <map>
@@ -36,7 +36,7 @@ private:
public:
mutable CCriticalSection cs_db;
- DbEnv *dbenv;
+ std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb;
@@ -45,7 +45,7 @@ public:
void Reset();
void MakeMock();
- bool IsMock() { return fMockDb; }
+ bool IsMock() const { return fMockDb; }
/**
* Verify that database file strFile is OK. If it is not,
@@ -156,6 +156,9 @@ public:
explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
~CDB() { Close(); }
+ CDB(const CDB&) = delete;
+ CDB& operator=(const CDB&) = delete;
+
void Flush();
void Close();
static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
@@ -164,13 +167,9 @@ public:
ideal to be called periodically */
static bool PeriodicFlush(CWalletDBWrapper& dbw);
/* verifies the database environment */
- static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
+ static bool VerifyEnvironment(const std::string& walletFile, const fs::path& walletDir, std::string& errorStr);
/* verifies the database file */
- static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
-
-private:
- CDB(const CDB&);
- void operator=(const CDB&);
+ static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& walletDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
public:
template <typename K, typename T>
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index c1ea2b6290..9bfcab54a5 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -2,18 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/validation.h"
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/wallet.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "validation.h" //for mempool access
-#include "txmempool.h"
-#include "utilmoneystr.h"
-#include "util.h"
-#include "net.h"
+#include <consensus/validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <validation.h> //for mempool access
+#include <txmempool.h>
+#include <utilmoneystr.h>
+#include <util.h>
+#include <net.h>
// Calculate the size of the transaction assuming all signatures are max size
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
@@ -22,7 +23,7 @@
// calculation, but we should be able to refactor after priority is removed).
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)
+static int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet)
{
CMutableTransaction txNew(tx);
std::vector<CInputCoin> vCoins;
@@ -30,11 +31,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// wallet, with a valid index into the vout array.
for (auto& input : tx.vin) {
- const auto mi = pWallet->mapWallet.find(input.prevout.hash);
- assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
+ const auto mi = wallet->mapWallet.find(input.prevout.hash);
+ assert(mi != wallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
vCoins.emplace_back(CInputCoin(&(mi->second), input.prevout.n));
}
- if (!pWallet->DummySignTx(txNew, vCoins)) {
+ if (!wallet->DummySignTx(txNew, vCoins)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
return -1;
@@ -42,103 +43,102 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
return GetVirtualTransactionSize(txNew);
}
-bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx) {
- if (pWallet->HasWalletSpend(wtx.GetHash())) {
- vErrors.push_back("Transaction has descendants in the wallet");
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return false;
+//! Check whether transaction has descendant in wallet or mempool, or has been
+//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
+static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors)
+{
+ if (wallet->HasWalletSpend(wtx.GetHash())) {
+ errors.push_back("Transaction has descendants in the wallet");
+ return feebumper::Result::INVALID_PARAMETER;
}
{
LOCK(mempool.cs);
auto it_mp = mempool.mapTx.find(wtx.GetHash());
if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
- vErrors.push_back("Transaction has descendants in the mempool");
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return false;
+ errors.push_back("Transaction has descendants in the mempool");
+ return feebumper::Result::INVALID_PARAMETER;
}
}
if (wtx.GetDepthInMainChain() != 0) {
- vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return false;
+ errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
+ return feebumper::Result::WALLET_ERROR;
}
- return true;
+ return feebumper::Result::OK;
}
-CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee)
- :
- txid(std::move(txidIn)),
- nOldFee(0),
- nNewFee(0)
+namespace feebumper {
+
+bool TransactionCanBeBumped(CWallet* wallet, const uint256& txid)
{
- vErrors.clear();
- bumpedTxid.SetNull();
- AssertLockHeld(pWallet->cs_wallet);
- if (!pWallet->mapWallet.count(txid)) {
- vErrors.push_back("Invalid or non-wallet transaction id");
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
- return;
+ LOCK2(cs_main, wallet->cs_wallet);
+ const CWalletTx* wtx = wallet->GetWalletTx(txid);
+ return wtx && SignalsOptInRBF(*wtx->tx) && !wtx->mapValue.count("replaced_by_txid");
+}
+
+Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
+ CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
+{
+ LOCK2(cs_main, wallet->cs_wallet);
+ errors.clear();
+ auto it = wallet->mapWallet.find(txid);
+ if (it == wallet->mapWallet.end()) {
+ errors.push_back("Invalid or non-wallet transaction id");
+ return Result::INVALID_ADDRESS_OR_KEY;
}
- auto it = pWallet->mapWallet.find(txid);
const CWalletTx& wtx = it->second;
- if (!preconditionChecks(pWallet, wtx)) {
- return;
+ Result result = PreconditionChecks(wallet, wtx, errors);
+ if (result != Result::OK) {
+ return result;
}
- if (!SignalsOptInRBF(wtx)) {
- vErrors.push_back("Transaction is not BIP 125 replaceable");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (!SignalsOptInRBF(*wtx.tx)) {
+ errors.push_back("Transaction is not BIP 125 replaceable");
+ return Result::WALLET_ERROR;
}
if (wtx.mapValue.count("replaced_by_txid")) {
- vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
+ return Result::WALLET_ERROR;
}
// check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
- if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
- vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (!wallet->IsAllFromMe(*wtx.tx, ISMINE_SPENDABLE)) {
+ errors.push_back("Transaction contains inputs that don't belong to this wallet");
+ return Result::WALLET_ERROR;
}
// figure out which output was change
// if there was no change output or multiple change outputs, fail
int nOutput = -1;
for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
- if (pWallet->IsChange(wtx.tx->vout[i])) {
+ if (wallet->IsChange(wtx.tx->vout[i])) {
if (nOutput != -1) {
- vErrors.push_back("Transaction has multiple change outputs");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Transaction has multiple change outputs");
+ return Result::WALLET_ERROR;
}
nOutput = i;
}
}
if (nOutput == -1) {
- vErrors.push_back("Transaction does not have a change output");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Transaction does not have a change output");
+ return Result::WALLET_ERROR;
}
// Calculate the expected size of the new transaction.
int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
- const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, pWallet);
+ const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, wallet);
if (maxNewTxSize < 0) {
- vErrors.push_back("Transaction contains inputs that cannot be signed");
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
- return;
+ errors.push_back("Transaction contains inputs that cannot be signed");
+ return Result::INVALID_ADDRESS_OR_KEY;
}
// calculate the old fee and fee-rate
- nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
- CFeeRate nOldFeeRate(nOldFee, txSize);
+ old_fee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
+ CFeeRate nOldFeeRate(old_fee, txSize);
CFeeRate nNewFeeRate;
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// future proof against changes to network wide policy for incremental relay
@@ -148,26 +148,24 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
walletIncrementalRelayFee = ::incrementalRelayFee;
}
- if (totalFee > 0) {
+ if (total_fee > 0) {
CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
- if (totalFee < minTotalFee) {
- vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
+ if (total_fee < minTotalFee) {
+ errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return;
+ return Result::INVALID_PARAMETER;
}
- CAmount requiredFee = CWallet::GetRequiredFee(maxNewTxSize);
- if (totalFee < requiredFee) {
- vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
+ CAmount requiredFee = GetRequiredFee(maxNewTxSize);
+ if (total_fee < requiredFee) {
+ errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
FormatMoney(requiredFee)));
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return;
+ return Result::INVALID_PARAMETER;
}
- nNewFee = totalFee;
- nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
+ new_fee = total_fee;
+ nNewFeeRate = CFeeRate(total_fee, maxNewTxSize);
} else {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
- nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
+ new_fee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nNewFeeRate = CFeeRate(new_fee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate
// walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
@@ -176,47 +174,50 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
// add 1 satoshi to the result, because it may have been rounded down.
if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
- nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
+ new_fee = nNewFeeRate.GetFee(maxNewTxSize);
}
}
// Check that in all cases the new fee doesn't violate maxTxFee
- if (nNewFee > maxTxFee) {
- vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
- FormatMoney(nNewFee), FormatMoney(maxTxFee)));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (new_fee > maxTxFee) {
+ errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
+ FormatMoney(new_fee), FormatMoney(maxTxFee)));
+ return Result::WALLET_ERROR;
}
// check that fee rate is higher than mempool's minimum fee
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
- // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
+ // moment earlier. In this case, we report an error to the user, who may use total_fee to make an adjustment.
CFeeRate minMempoolFeeRate = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
- vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back(strprintf(
+ "New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
+ "the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction",
+ FormatMoney(nNewFeeRate.GetFeePerK()),
+ FormatMoney(minMempoolFeeRate.GetFeePerK()),
+ FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)),
+ FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ return Result::WALLET_ERROR;
}
// Now modify the output to increase the fee.
// If the output is not large enough to pay the fee, fail.
- CAmount nDelta = nNewFee - nOldFee;
+ CAmount nDelta = new_fee - old_fee;
assert(nDelta > 0);
mtx = *wtx.tx;
CTxOut* poutput = &(mtx.vout[nOutput]);
if (poutput->nValue < nDelta) {
- vErrors.push_back("Change output is too small to bump the fee");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Change output is too small to bump the fee");
+ return Result::WALLET_ERROR;
}
// If the output would become dust, discard it (converting the dust to fee)
poutput->nValue -= nDelta;
if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {
LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
- nNewFee += poutput->nValue;
+ new_fee += poutput->nValue;
mtx.vout.erase(mtx.vout.begin() + nOutput);
}
@@ -227,35 +228,36 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
}
}
- currentResult = BumpFeeResult::OK;
+ return Result::OK;
}
-bool CFeeBumper::signTransaction(CWallet *pWallet)
-{
- return pWallet->SignTransaction(mtx);
+bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx) {
+ LOCK2(cs_main, wallet->cs_wallet);
+ return wallet->SignTransaction(mtx);
}
-bool CFeeBumper::commit(CWallet *pWallet)
+Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid)
{
- AssertLockHeld(pWallet->cs_wallet);
- if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
- return false;
+ LOCK2(cs_main, wallet->cs_wallet);
+ if (!errors.empty()) {
+ return Result::MISC_ERROR;
}
- if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
- vErrors.push_back("Invalid or non-wallet transaction id");
- currentResult = BumpFeeResult::MISC_ERROR;
- return false;
+ auto it = txid.IsNull() ? wallet->mapWallet.end() : wallet->mapWallet.find(txid);
+ if (it == wallet->mapWallet.end()) {
+ errors.push_back("Invalid or non-wallet transaction id");
+ return Result::MISC_ERROR;
}
- CWalletTx& oldWtx = pWallet->mapWallet[txid];
+ CWalletTx& oldWtx = it->second;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
- if (!preconditionChecks(pWallet, oldWtx)) {
- return false;
+ Result result = PreconditionChecks(wallet, oldWtx, errors);
+ if (result != Result::OK) {
+ return result;
}
- CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
+ CWalletTx wtxBumped(wallet, MakeTransactionRef(std::move(mtx)));
// commit/broadcast the tx
- CReserveKey reservekey(pWallet);
+ CReserveKey reservekey(wallet);
wtxBumped.mapValue = oldWtx.mapValue;
wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
wtxBumped.vOrderForm = oldWtx.vOrderForm;
@@ -263,27 +265,29 @@ bool CFeeBumper::commit(CWallet *pWallet)
wtxBumped.fTimeReceivedIsTxTime = true;
wtxBumped.fFromMe = true;
CValidationState state;
- if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
+ if (!wallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
// NOTE: CommitTransaction never returns false, so this should never happen.
- vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
- return false;
+ errors.push_back(strprintf("The transaction was rejected: %s", state.GetRejectReason()));
+ return Result::WALLET_ERROR;
}
- bumpedTxid = wtxBumped.GetHash();
+ bumped_txid = wtxBumped.GetHash();
if (state.IsInvalid()) {
// This can happen if the mempool rejected the transaction. Report
// what happened in the "errors" response.
- vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
+ errors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
}
// mark the original tx as bumped
- if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
+ if (!wallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
// TODO: see if JSON-RPC has a standard way of returning a response
// along with an exception. It would be good to return information about
// wtxBumped to the caller even if marking the original transaction
// replaced does not succeed for some reason.
- vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
+ errors.push_back("Created new bumpfee transaction but could not mark the original transaction as replaced");
}
- return true;
+ return Result::OK;
}
+} // namespace feebumper
+
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index 3d64e53c15..8eec30440c 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -13,7 +13,9 @@ class uint256;
class CCoinControl;
enum class FeeEstimateMode;
-enum class BumpFeeResult
+namespace feebumper {
+
+enum class Result
{
OK,
INVALID_ADDRESS_OR_KEY,
@@ -23,39 +25,34 @@ enum class BumpFeeResult
MISC_ERROR,
};
-class CFeeBumper
-{
-public:
- CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee);
- BumpFeeResult getResult() const { return currentResult; }
- const std::vector<std::string>& getErrors() const { return vErrors; }
- CAmount getOldFee() const { return nOldFee; }
- CAmount getNewFee() const { return nNewFee; }
- uint256 getBumpedTxId() const { return bumpedTxid; }
-
- /* signs the new transaction,
- * returns false if the tx couldn't be found or if it was
- * impossible to create the signature(s)
- */
- bool signTransaction(CWallet *pWallet);
-
- /* commits the fee bump,
- * returns true, in case of CWallet::CommitTransaction was successful
- * but, eventually sets vErrors if the tx could not be added to the mempool (will try later)
- * or if the old transaction could not be marked as replaced
- */
- bool commit(CWallet *pWalletNonConst);
-
-private:
- bool preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx);
-
- const uint256 txid;
- uint256 bumpedTxid;
- CMutableTransaction mtx;
- std::vector<std::string> vErrors;
- BumpFeeResult currentResult;
- CAmount nOldFee;
- CAmount nNewFee;
-};
+//! Return whether transaction can be bumped.
+bool TransactionCanBeBumped(CWallet* wallet, const uint256& txid);
+
+//! Create bumpfee transaction.
+Result CreateTransaction(const CWallet* wallet,
+ const uint256& txid,
+ const CCoinControl& coin_control,
+ CAmount total_fee,
+ std::vector<std::string>& errors,
+ CAmount& old_fee,
+ CAmount& new_fee,
+ CMutableTransaction& mtx);
+
+//! Sign the new transaction,
+//! @return false if the tx couldn't be found or if it was
+//! impossible to create the signature(s)
+bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx);
+
+//! Commit the bumpfee transaction.
+//! @return success in case of CWallet::CommitTransaction was successful,
+//! but sets errors if the tx could not be added to the mempool (will try later)
+//! or if the old transaction could not be marked as replaced.
+Result CommitTransaction(CWallet* wallet,
+ const uint256& txid,
+ CMutableTransaction&& mtx,
+ std::vector<std::string>& errors,
+ uint256& bumped_txid);
+
+} // namespace feebumper
#endif // BITCOIN_WALLET_FEEBUMPER_H
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
new file mode 100644
index 0000000000..73985dcf25
--- /dev/null
+++ b/src/wallet/fees.cpp
@@ -0,0 +1,89 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <wallet/fees.h>
+
+#include <policy/policy.h>
+#include <txmempool.h>
+#include <util.h>
+#include <validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/wallet.h>
+
+
+CAmount GetRequiredFee(unsigned int nTxBytes)
+{
+ return std::max(CWallet::minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
+}
+
+
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
+{
+ /* User control of how to calculate fee uses the following parameter precedence:
+ 1. coin_control.m_feerate
+ 2. coin_control.m_confirm_target
+ 3. payTxFee (user-set global variable)
+ 4. nTxConfirmTarget (user-set global variable)
+ The first parameter that is set is used.
+ */
+ CAmount fee_needed;
+ if (coin_control.m_feerate) { // 1.
+ fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ // Allow to override automatic min/max check over coin control instance
+ if (coin_control.fOverrideFeeRate) return fee_needed;
+ }
+ else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
+ fee_needed = ::payTxFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ }
+ else { // 2. or 4.
+ // We will use smart fee estimation
+ unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
+ // By default estimates are economical iff we are signaling opt-in-RBF
+ bool conservative_estimate = !coin_control.signalRbf;
+ // Allow to override the default fee estimate mode over the CoinControl instance
+ if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
+ else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
+
+ fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
+ if (fee_needed == 0) {
+ // if we don't have enough data for estimateSmartFee, then use fallbackFee
+ fee_needed = CWallet::fallbackFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
+ }
+ // Obey mempool min fee when using smart fee estimation
+ CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
+ if (fee_needed < min_mempool_fee) {
+ fee_needed = min_mempool_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
+ }
+ }
+
+ // prevent user from paying a fee below minRelayTxFee or minTxFee
+ CAmount required_fee = GetRequiredFee(nTxBytes);
+ if (required_fee > fee_needed) {
+ fee_needed = required_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
+ }
+ // But always obey the maximum
+ if (fee_needed > maxTxFee) {
+ fee_needed = maxTxFee;
+ if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
+ }
+ return fee_needed;
+}
+
+
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
+{
+ unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
+ // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
+ discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
+ // Discard rate must be at least dustRelayFee
+ discard_rate = std::max(discard_rate, ::dustRelayFee);
+ return discard_rate;
+}
diff --git a/src/wallet/fees.h b/src/wallet/fees.h
new file mode 100644
index 0000000000..225aff08ad
--- /dev/null
+++ b/src/wallet/fees.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_FEES_H
+#define BITCOIN_WALLET_FEES_H
+
+#include <amount.h>
+
+class CBlockPolicyEstimator;
+class CCoinControl;
+class CFeeRate;
+class CTxMemPool;
+struct FeeCalculation;
+
+/**
+ * Return the minimum required fee taking into account the
+ * floating relay fee and user set minimum transaction fee
+ */
+CAmount GetRequiredFee(unsigned int nTxBytes);
+
+/**
+ * Estimate the minimum fee considering user set parameters
+ * and the required fee
+ */
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
+
+/**
+ * Return the maximum feerate for discarding change.
+ */
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator);
+
+#endif // BITCOIN_WALLET_FEES_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
new file mode 100644
index 0000000000..67c46df87d
--- /dev/null
+++ b/src/wallet/init.cpp
@@ -0,0 +1,295 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <wallet/init.h>
+
+#include <net.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validation.h>
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
+#include <wallet/walletutil.h>
+
+std::string GetWalletHelpString(bool showDebug)
+{
+ std::string strUsage = HelpMessageGroup(_("Wallet options:"));
+ strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
+ strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
+ strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
+ strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
+ "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
+ strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
+ strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
+ strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
+ strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
+ strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
+ strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
+ strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
+ strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
+ strUsage += HelpMessageOpt("-walletdir=<dir>", _("Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)"));
+ strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
+ strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
+ " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
+
+ if (showDebug)
+ {
+ strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
+
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
+ strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
+ }
+
+ return strUsage;
+}
+
+bool WalletParameterInteraction()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
+ LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);
+ }
+
+ return true;
+ }
+
+ gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
+ const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
+
+ if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
+ LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
+ }
+ // Rewrite just private keys: rescan to find transactions
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ }
+ }
+
+ int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
+ // -zapwallettxes implies dropping the mempool on startup
+ if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
+ }
+
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
+ }
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
+ }
+ }
+
+ if (is_multiwallet) {
+ if (gArgs.GetBoolArg("-upgradewallet", false)) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
+ }
+ }
+
+ if (gArgs.GetBoolArg("-sysperms", false))
+ return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
+ if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
+
+ if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
+ _("The wallet will avoid paying less than the minimum relay fee."));
+
+ if (gArgs.IsArgSet("-mintxfee"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
+ if (n > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-mintxfee") + " " +
+ _("This is the minimum transaction fee you pay on every transaction."));
+ CWallet::minTxFee = CFeeRate(n);
+ }
+ if (gArgs.IsArgSet("-fallbackfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-fallbackfee") + " " +
+ _("This is the transaction fee you may pay when fee estimates are not available."));
+ CWallet::fallbackFee = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-discardfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-discardfee") + " " +
+ _("This is the transaction fee you may discard if change is smaller than dust at this level"));
+ CWallet::m_discard_rate = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-paytxfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
+ return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-paytxfee") + " " +
+ _("This is the transaction fee you will pay if you send a transaction."));
+
+ payTxFee = CFeeRate(nFeePerK, 1000);
+ if (payTxFee < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+ gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ if (gArgs.IsArgSet("-maxtxfee"))
+ {
+ CAmount nMaxFee = 0;
+ if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
+ return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
+ if (nMaxFee > HIGH_MAX_TX_FEE)
+ InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+ maxTxFee = nMaxFee;
+ if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
+ bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
+ fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
+
+ return true;
+}
+
+void RegisterWalletRPC(CRPCTable &t)
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ return;
+ }
+
+ RegisterWalletRPCCommands(t);
+}
+
+bool VerifyWallets()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ return true;
+ }
+
+ if (gArgs.IsArgSet("-walletdir") && !fs::is_directory(GetWalletDir())) {
+ return InitError(strprintf(_("Error: Specified wallet directory \"%s\" does not exist."), gArgs.GetArg("-walletdir", "").c_str()));
+ }
+
+ LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
+
+ uiInterface.InitMessage(_("Verifying wallet(s)..."));
+
+ // Keep track of each wallet absolute path to detect duplicates.
+ std::set<fs::path> wallet_paths;
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ if (boost::filesystem::path(walletFile).filename() != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
+ }
+
+ if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile));
+ }
+
+ fs::path wallet_path = fs::absolute(walletFile, GetWalletDir());
+
+ if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile));
+ }
+
+ if (!wallet_paths.insert(wallet_path).second) {
+ return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
+ }
+
+ std::string strError;
+ if (!CWalletDB::VerifyEnvironment(walletFile, GetWalletDir().string(), strError)) {
+ return InitError(strError);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ // Recover readable keypairs:
+ CWallet dummyWallet;
+ std::string backup_filename;
+ if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
+ return false;
+ }
+ }
+
+ std::string strWarning;
+ bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetWalletDir().string(), strWarning, strError);
+ if (!strWarning.empty()) {
+ InitWarning(strWarning);
+ }
+ if (!dbV) {
+ InitError(strError);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool OpenWallets()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile);
+ if (!pwallet) {
+ return false;
+ }
+ vpwallets.push_back(pwallet);
+ }
+
+ return true;
+}
+
+void StartWallets(CScheduler& scheduler) {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->postInitProcess(scheduler);
+ }
+}
+
+void FlushWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->Flush(false);
+ }
+}
+
+void StopWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->Flush(true);
+ }
+}
+
+void CloseWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ delete pwallet;
+ }
+ vpwallets.clear();
+}
diff --git a/src/wallet/init.h b/src/wallet/init.h
new file mode 100644
index 0000000000..0b3ee2dda2
--- /dev/null
+++ b/src/wallet/init.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_INIT_H
+#define BITCOIN_WALLET_INIT_H
+
+#include <string>
+
+class CRPCTable;
+class CScheduler;
+
+//! Return the wallets help message.
+std::string GetWalletHelpString(bool showDebug);
+
+//! Wallets parameter interaction
+bool WalletParameterInteraction();
+
+//! Register wallet RPCs.
+void RegisterWalletRPC(CRPCTable &tableRPC);
+
+//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
+// This function will perform salvage on the wallet if requested, as long as only one wallet is
+// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+bool VerifyWallets();
+
+//! Load wallet databases.
+bool OpenWallets();
+
+//! Complete startup of wallets.
+void StartWallets(CScheduler& scheduler);
+
+//! Flush all wallets in preparation for shutdown.
+void FlushWallets();
+
+//! Stop all wallets. Wallets will be flushed first.
+void StopWallets();
+
+//! Close all wallets.
+void CloseWallets();
+
+#endif // BITCOIN_WALLET_INIT_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index d23adc84fc..6ca947bf1b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -2,21 +2,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "rpc/server.h"
-#include "init.h"
-#include "validation.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "sync.h"
-#include "util.h"
-#include "utiltime.h"
-#include "wallet.h"
-#include "merkleblock.h"
-#include "core_io.h"
-
-#include "rpcwallet.h"
+#include <base58.h>
+#include <chain.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <wallet/init.h>
+#include <validation.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
+#include <util.h>
+#include <utiltime.h>
+#include <wallet/wallet.h>
+#include <merkleblock.h>
+#include <core_io.h>
+
+#include <wallet/rpcwallet.h>
#include <fstream>
#include <stdint.h>
@@ -79,10 +80,10 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
- "importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n"
- "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
+ "importprivkey \"privkey\" ( \"label\" ) ( rescan )\n"
+ "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
"\nArguments:\n"
- "1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
+ "1. \"privkey\" (string, required) The private key (see dumpprivkey)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
@@ -164,7 +165,7 @@ UniValue abortrescan(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
"abortrescan\n"
- "\nStops current wallet rescan triggered e.g. by an importprivkey call.\n"
+ "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
"\nExamples:\n"
"\nImport a private key\n"
+ HelpExampleCli("importprivkey", "\"mykey\"") +
@@ -174,12 +175,13 @@ UniValue abortrescan(const JSONRPCRequest& request)
+ HelpExampleRpc("abortrescan", "")
);
+ ObserveSafeMode();
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
return true;
}
-void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
+void ImportAddress(CWallet*, const CTxDestination& dest, 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) {
@@ -196,7 +198,7 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel);
+ ImportAddress(pwallet, CScriptID(script), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
@@ -205,13 +207,13 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
}
}
-void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel)
+void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel)
{
- CScript script = GetScriptForDestination(address.Get());
+ CScript script = GetScriptForDestination(dest);
ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
- if (address.IsValid())
- pwallet->SetAddressBook(address.Get(), strLabel, "receive");
+ if (IsValidDestination(dest))
+ pwallet->SetAddressBook(dest, strLabel, "receive");
}
UniValue importaddress(const JSONRPCRequest& request)
@@ -224,7 +226,7 @@ UniValue importaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
"importaddress \"address\" ( \"label\" rescan p2sh )\n"
- "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"script\" (string, required) The hex-encoded script (or address)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
@@ -263,11 +265,12 @@ UniValue importaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (address.IsValid()) {
- if (fP2SH)
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (IsValidDestination(dest)) {
+ if (fP2SH) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
- ImportAddress(pwallet, address, strLabel);
+ }
+ ImportAddress(pwallet, dest, strLabel);
} else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
@@ -337,7 +340,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (pwallet->IsMine(wtx)) {
+ if (pwallet->IsMine(*wtx.tx)) {
pwallet->AddToWallet(wtx, false);
return NullUniValue;
}
@@ -393,7 +396,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
- "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"pubkey\" (string, required) The hex-encoded public key\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
@@ -430,7 +433,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel);
+ ImportAddress(pwallet, pubKey.GetID(), strLabel);
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan)
@@ -453,7 +456,7 @@ UniValue importwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"importwallet \"filename\"\n"
- "\nImports keys from a wallet dump file (see dumpwallet).\n"
+ "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The wallet file\n"
"\nExamples:\n"
@@ -504,7 +507,7 @@ UniValue importwallet(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
- LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
+ LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
continue;
}
int64_t nTime = DecodeDumpTime(vstr[1]);
@@ -522,7 +525,7 @@ UniValue importwallet(const JSONRPCRequest& request)
fLabel = true;
}
}
- LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
+ LogPrintf("Importing %s...\n", EncodeDestination(keyid));
if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
@@ -571,14 +574,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
std::string strAddress = request.params[0].get_str();
- CBitcoinAddress address;
- if (!address.SetString(strAddress))
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
+ }
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
+ }
CKey vchSecret;
- if (!pwallet->GetKey(keyID, vchSecret)) {
+ if (!pwallet->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
}
return CBitcoinSecret(vchSecret).ToString();
@@ -595,7 +600,10 @@ UniValue dumpwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"dumpwallet \"filename\"\n"
- "\nDumps all wallet keys in a human-readable format.\n"
+ "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
+ "Imported scripts are not currently included in wallet dumps, these must be backed up separately.\n"
+ "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n"
+ "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n"
"\nResult:\n"
@@ -611,9 +619,19 @@ UniValue dumpwallet(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- std::ofstream file;
boost::filesystem::path filepath = request.params[0].get_str();
filepath = boost::filesystem::absolute(filepath);
+
+ /* Prevent arbitrary files from being overwritten. There have been reports
+ * that users have overwritten wallet files this way:
+ * https://github.com/bitcoin/bitcoin/issues/9934
+ * It may also avoid other security issues.
+ */
+ if (boost::filesystem::exists(filepath)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
+ }
+
+ std::ofstream file;
file.open(filepath.string().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@@ -657,7 +675,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
std::string strTime = EncodeDumpTime(it->first);
- std::string strAddr = CBitcoinAddress(keyid).ToString();
+ std::string strAddr = EncodeDestination(keyid);
CKey key;
if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
@@ -713,14 +731,14 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
// Parse the output.
CScript script;
- CBitcoinAddress address;
+ CTxDestination dest;
if (!isScript) {
- address = CBitcoinAddress(output);
- if (!address.IsValid()) {
+ dest = DecodeDestination(output);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
- script = GetScriptForDestination(address.Get());
+ script = GetScriptForDestination(dest);
} else {
if (!IsHex(output)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
@@ -778,8 +796,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript));
- CScript redeemDestination = GetScriptForDestination(redeemAddress.Get());
+ CTxDestination redeem_dest = CScriptID(redeemScript);
+ CScript redeemDestination = GetScriptForDestination(redeem_dest);
if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -792,8 +810,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
- if (address.IsValid()) {
- pwallet->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
// Import private keys.
@@ -852,27 +870,25 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
}
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
}
- CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());
+ CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -885,8 +901,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
- if (pubKeyAddress.IsValid()) {
- pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive");
+ if (IsValidDestination(pubkey_dest)) {
+ pwallet->SetAddressBook(pubkey_dest, label, "receive");
}
// TODO Is this necessary?
@@ -925,21 +941,19 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
CPubKey pubKey = key.GetPubKey();
assert(key.VerifyPubKey(pubKey));
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
@@ -950,7 +964,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
pwallet->SetAddressBook(vchAddress, label, "receive");
if (pwallet->HaveKey(vchAddress)) {
- return false;
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
@@ -978,8 +992,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
if (scriptPubKey.getType() == UniValue::VOBJ) {
// add to address book or update label
- if (address.IsValid()) {
- pwallet->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
}
@@ -1028,7 +1042,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
throw std::runtime_error(
"importmulti \"requests\" ( \"options\" )\n\n"
- "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n"
+ "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n\n"
"Arguments:\n"
"1. requests (array, required) Data to be imported\n"
" [ (array of json objects)\n"
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index a6176c3485..473acd8367 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3,29 +3,32 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "amount.h"
-#include "base58.h"
-#include "chain.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "init.h"
-#include "httpserver.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "rpc/mining.h"
-#include "rpc/server.h"
-#include "script/sign.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <amount.h>
+#include <base58.h>
+#include <chain.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <httpserver.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <rpc/mining.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <script/sign.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
+#include <wallet/walletutil.h>
+
+#include <init.h> // For StartShutdown
#include <stdint.h>
@@ -106,7 +109,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
std::string rbfStatus = "no";
if (confirms <= 0) {
LOCK(mempool.cs);
- RBFTransactionState rbfState = IsRBFOptIn(wtx, mempool);
+ RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool);
if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN)
rbfStatus = "unknown";
else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125)
@@ -168,18 +171,18 @@ UniValue getnewaddress(const JSONRPCRequest& request)
pwallet->SetAddressBook(keyID, strAccount, "receive");
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
-CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
+CTxDestination GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
{
CPubKey pubKey;
if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
- return CBitcoinAddress(pubKey.GetID());
+ return pubKey.GetID();
}
UniValue getaccountaddress(const JSONRPCRequest& request)
@@ -211,7 +214,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
UniValue ret(UniValue::VSTR);
- ret = GetAccountAddress(pwallet, strAccount).ToString();
+ ret = EncodeDestination(GetAccountAddress(pwallet, strAccount));
return ret;
}
@@ -250,7 +253,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
CKeyID keyID = vchPubKey.GetID();
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
@@ -275,24 +278,25 @@ UniValue setaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
std::string strAccount;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
- if (IsMine(*pwallet, address.Get())) {
+ if (IsMine(*pwallet, dest)) {
// Detect when changing the account of an address that is the 'unused current key' of another account:
- if (pwallet->mapAddressBook.count(address.Get())) {
- std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
- if (address == GetAccountAddress(pwallet, strOldAccount)) {
+ if (pwallet->mapAddressBook.count(dest)) {
+ std::string strOldAccount = pwallet->mapAddressBook[dest].name;
+ if (dest == GetAccountAddress(pwallet, strOldAccount)) {
GetAccountAddress(pwallet, strOldAccount, true);
}
}
- pwallet->SetAddressBook(address.Get(), strAccount, "receive");
+ pwallet->SetAddressBook(dest, strAccount, "receive");
}
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
@@ -323,12 +327,13 @@ UniValue getaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
std::string strAccount;
- std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get());
+ std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
}
@@ -365,11 +370,12 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
// 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;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
const std::string& strName = item.second.name;
- if (strName == strAccount)
- ret.push_back(address.ToString());
+ if (strName == strAccount) {
+ ret.push_back(EncodeDestination(dest));
+ }
}
return ret;
}
@@ -449,11 +455,18 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
// Amount
CAmount nAmount = AmountFromValue(request.params[1]);
@@ -462,26 +475,26 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
// Wallet comments
CWalletTx wtx;
- if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
+ if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str();
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (request.params.size() > 4 && !request.params[4].isNull()) {
+ if (!request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
}
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -490,7 +503,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control);
+ SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control);
return wtx.GetHash().GetHex();
}
@@ -525,20 +538,26 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
+ HelpExampleRpc("listaddressgroupings", "")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
- for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
+ for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
- for (CTxDestination address : grouping)
+ for (const CTxDestination& address : grouping)
{
UniValue addressInfo(UniValue::VARR);
- addressInfo.push_back(CBitcoinAddress(address).ToString());
+ addressInfo.push_back(EncodeDestination(address));
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) {
- addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
+ if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
+ addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
}
}
jsonGrouping.push_back(addressInfo);
@@ -583,16 +602,18 @@ UniValue signmessage(const JSONRPCRequest& request)
std::string strAddress = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
CKey key;
- if (!pwallet->GetKey(keyID, key)) {
+ if (!pwallet->GetKey(*keyID, key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
}
@@ -604,7 +625,7 @@ UniValue signmessage(const JSONRPCRequest& request)
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
- return EncodeBase64(&vchSig[0], vchSig.size());
+ return EncodeBase64(vchSig.data(), vchSig.size());
}
UniValue getreceivedbyaddress(const JSONRPCRequest& request)
@@ -634,15 +655,22 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
- CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ }
+ CScript scriptPubKey = GetScriptForDestination(dest);
if (!IsMine(*pwallet, scriptPubKey)) {
- return ValueFromAmount(0);
+ throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
}
// Minimum confirmations
@@ -694,6 +722,12 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
@@ -766,20 +800,39 @@ UniValue getbalance(const JSONRPCRequest& request)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 0)
- return ValueFromAmount(pwallet->GetBalance());
+ const UniValue& account_value = request.params[0];
+ const UniValue& minconf = request.params[1];
+ const UniValue& include_watchonly = request.params[2];
- const std::string& account_param = request.params[0].get_str();
+ if (account_value.isNull()) {
+ if (!minconf.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance minconf option is only currently supported if an account is specified");
+ }
+ if (!include_watchonly.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance include_watchonly option is only currently supported if an account is specified");
+ }
+ return ValueFromAmount(pwallet->GetBalance());
+ }
+
+ const std::string& account_param = account_value.get_str();
const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1;
- if (!request.params[1].isNull())
- nMinDepth = request.params[1].get_int();
+ if (!minconf.isNull())
+ nMinDepth = minconf.get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(!request.params[2].isNull())
- if(request.params[2].get_bool())
+ if(!include_watchonly.isNull())
+ if(include_watchonly.get_bool())
filter = filter | ISMINE_WATCH_ONLY;
return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
@@ -797,6 +850,12 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request)
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetUnconfirmedBalance());
@@ -831,6 +890,7 @@ UniValue movecmd(const JSONRPCRequest& request)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strFrom = AccountFromValue(request.params[0]);
@@ -838,11 +898,11 @@ UniValue movecmd(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
std::string strComment;
- if (request.params.size() > 4)
+ if (!request.params[4].isNull())
strComment = request.params[4].get_str();
if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
@@ -889,24 +949,31 @@ UniValue sendfrom(const JSONRPCRequest& request)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = AccountFromValue(request.params[0]);
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
+ if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str();
- if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
+ if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet);
@@ -917,7 +984,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
CCoinControl no_coin_control; // This is a deprecated API
- SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control);
+ SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control);
return wtx.GetHash().GetHex();
}
@@ -972,6 +1039,12 @@ UniValue sendmany(const JSONRPCRequest& request)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
@@ -986,44 +1059,45 @@ UniValue sendmany(const JSONRPCRequest& request)
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (request.params.size() > 4 && !request.params[4].isNull())
+ if (!request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
}
- std::set<CBitcoinAddress> setAddress;
+ std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
std::vector<std::string> keys = sendTo.getKeys();
- for (const std::string& name_ : keys)
- {
- CBitcoinAddress address(name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
+ for (const std::string& name_ : keys) {
+ CTxDestination dest = DecodeDestination(name_);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (destinations.count(dest)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
+ destinations.insert(dest);
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(dest);
CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@@ -1077,7 +1151,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
- "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
+ "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
@@ -1105,7 +1179,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
@@ -1114,18 +1188,17 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
pwallet->AddCScript(inner);
pwallet->SetAddressBook(innerID, strAccount, "send");
- return CBitcoinAddress(innerID).ToString();
+ return EncodeDestination(innerID);
}
class Witnessifier : public boost::static_visitor<bool>
{
public:
CWallet * const pwallet;
- CScriptID result;
-
- Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
+ CTxDestination result;
+ bool already_witness;
- bool operator()(const CNoDestination &dest) const { return false; }
+ explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
bool operator()(const CKeyID &keyID) {
if (pwallet) {
@@ -1134,14 +1207,12 @@ public:
SignatureData sigs;
// This check is to make sure that the script we created can actually be solved for and signed by us
// if we were to have the private keys. This is just to make sure that the script is valid and that,
- // if found in a transaction, we would still accept and relay that transcation.
+ // if found in a transaction, we would still accept and relay that transaction.
if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false;
}
- pwallet->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ return ExtractDestination(witscript, result);
}
return false;
}
@@ -1152,24 +1223,40 @@ public:
int witnessversion;
std::vector<unsigned char> witprog;
if (subscript.IsWitnessProgram(witnessversion, witprog)) {
- result = scriptID;
+ ExtractDestination(subscript, result);
+ already_witness = true;
return true;
}
CScript witscript = GetScriptForWitness(subscript);
SignatureData sigs;
// This check is to make sure that the script we created can actually be solved for and signed by us
// if we were to have the private keys. This is just to make sure that the script is valid and that,
- // if found in a transaction, we would still accept and relay that transcation.
+ // if found in a transaction, we would still accept and relay that transaction.
if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
return false;
}
- pwallet->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ return ExtractDestination(witscript, result);
}
return false;
}
+
+ bool operator()(const WitnessV0KeyHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ template<typename T>
+ bool operator()(const T& dest) { return false; }
};
UniValue addwitnessaddress(const JSONRPCRequest& request)
@@ -1179,17 +1266,18 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
{
- std::string msg = "addwitnessaddress \"address\"\n"
- "\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
+ std::string msg = "addwitnessaddress \"address\" ( p2sh )\n"
+ "\nAdd a witness address for a script (with pubkey or redeemscript known). Requires a new wallet backup.\n"
"It returns the witness script.\n"
"\nArguments:\n"
"1. \"address\" (string, required) An address known to the wallet\n"
+ "2. p2sh (bool, optional, default=true) Embed inside P2SH\n"
"\nResult:\n"
- "\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
+ "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n"
"}\n"
;
throw std::runtime_error(msg);
@@ -1202,20 +1290,38 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
}
}
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
+
+ bool p2sh = true;
+ if (!request.params[1].isNull()) {
+ p2sh = request.params[1].get_bool();
+ }
Witnessifier w(pwallet);
- CTxDestination dest = address.Get();
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
}
- pwallet->SetAddressBook(w.result, "", "receive");
+ CScript witprogram = GetScriptForDestination(w.result);
+
+ if (p2sh) {
+ w.result = CScriptID(witprogram);
+ }
+
+ if (w.already_witness) {
+ if (!(dest == w.result)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types");
+ }
+ } else {
+ pwallet->AddCScript(witprogram);
+ pwallet->SetAddressBook(w.result, "", "receive");
+ }
- return CBitcoinAddress(w.result).ToString();
+ return EncodeDestination(w.result);
}
struct tallyitem
@@ -1250,7 +1356,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
filter = filter | ISMINE_WATCH_ONLY;
// Tally
- std::map<CBitcoinAddress, tallyitem> mapTally;
+ std::map<CTxDestination, tallyitem> mapTally;
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
@@ -1283,10 +1389,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
// Reply
UniValue ret(UniValue::VARR);
std::map<std::string, tallyitem> mapAccountTally;
- for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
- const CBitcoinAddress& address = item.first;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
const std::string& strAccount = item.second.name;
- std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1312,7 +1418,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("address", address.ToString()));
+ obj.push_back(Pair("address", EncodeDestination(dest)));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
@@ -1333,14 +1439,14 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
if (fByAccounts)
{
- for (std::map<std::string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
+ for (const auto& entry : mapAccountTally)
{
- CAmount nAmount = (*it).second.nAmount;
- int nConf = (*it).second.nConf;
+ CAmount nAmount = entry.second.nAmount;
+ int nConf = entry.second.nConf;
UniValue obj(UniValue::VOBJ);
- if((*it).second.fIsWatchonly)
+ if (entry.second.fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("account", (*it).first));
+ obj.push_back(Pair("account", entry.first));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
ret.push_back(obj);
@@ -1389,6 +1495,12 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, false);
@@ -1428,6 +1540,12 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, true);
@@ -1435,9 +1553,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
- CBitcoinAddress addr;
- if (addr.Set(dest))
- entry.push_back(Pair("address", addr.ToString()));
+ if (IsValidDestination(dest)) {
+ entry.push_back(Pair("address", EncodeDestination(dest)));
+ }
}
/**
@@ -1615,6 +1733,12 @@ UniValue listtransactions(const JSONRPCRequest& request)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = "*";
@@ -1644,10 +1768,10 @@ UniValue listtransactions(const JSONRPCRequest& request)
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != 0)
+ if (pwtx != nullptr)
ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != 0)
+ if (pacentry != nullptr)
AcentryToJSON(*pacentry, strAccount, ret);
if ((int)ret.size() >= (nCount+nFrom)) break;
@@ -1708,13 +1832,19 @@ UniValue listaccounts(const JSONRPCRequest& request)
+ HelpExampleRpc("listaccounts", "6")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
@@ -1816,6 +1946,12 @@ UniValue listsinceblock(const JSONRPCRequest& request)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
@@ -1823,19 +1959,20 @@ UniValue listsinceblock(const JSONRPCRequest& request)
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (!request.params[0].isNull()) {
+ if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it != mapBlockIndex.end()) {
- paltindex = pindex = it->second;
- if (chainActive[pindex->nHeight] != pindex) {
- // the block being asked for is a part of a deactivated chain;
- // we don't want to depend on its perceived height in the block
- // chain, we want to instead use the last common ancestor
- pindex = chainActive.FindFork(pindex);
- }
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ paltindex = pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex) {
+ // the block being asked for is a part of a deactivated chain;
+ // we don't want to depend on its perceived height in the block
+ // chain, we want to instead use the last common ancestor
+ pindex = chainActive.FindFork(pindex);
}
}
@@ -1874,10 +2011,11 @@ UniValue listsinceblock(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
for (const CTransactionRef& tx : block.vtx) {
- if (pwallet->mapWallet.count(tx->GetHash()) > 0) {
+ auto it = pwallet->mapWallet.find(tx->GetHash());
+ if (it != pwallet->mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(pwallet, pwallet->mapWallet[tx->GetHash()], "*", -100000000, true, removed, filter);
+ ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter);
}
}
paltindex = paltindex->pprev;
@@ -1946,6 +2084,12 @@ UniValue gettransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -1957,10 +2101,11 @@ UniValue gettransaction(const JSONRPCRequest& request)
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
- if (!pwallet->mapWallet.count(hash)) {
+ auto it = pwallet->mapWallet.find(hash);
+ if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
- const CWalletTx& wtx = pwallet->mapWallet[hash];
+ const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
@@ -1977,7 +2122,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -2006,6 +2151,12 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -2040,6 +2191,10 @@ UniValue backupwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strDest = request.params[0].get_str();
@@ -2105,7 +2260,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
@@ -2169,7 +2324,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
@@ -2220,7 +2375,7 @@ UniValue walletlock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) {
+ if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
@@ -2260,7 +2415,7 @@ UniValue encryptwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) {
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
@@ -2359,27 +2514,33 @@ UniValue lockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 1)
- RPCTypeCheck(request.params, {UniValue::VBOOL});
- else
- RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VARR});
+ RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
bool fUnlock = request.params[0].get_bool();
- if (request.params.size() == 1) {
+ if (request.params[1].isNull()) {
if (fUnlock)
pwallet->UnlockAllCoins();
return true;
}
- UniValue outputs = request.params[1].get_array();
- for (unsigned int idx = 0; idx < outputs.size(); idx++) {
- const UniValue& output = outputs[idx];
- if (!output.isObject())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
- const UniValue& o = output.get_obj();
+ RPCTypeCheckArgument(request.params[1], UniValue::VARR);
+
+ const UniValue& output_params = request.params[1];
+
+ // Create and validate the COutPoints first.
+
+ std::vector<COutPoint> outputs;
+ outputs.reserve(output_params.size());
+
+ for (unsigned int idx = 0; idx < output_params.size(); idx++) {
+ const UniValue& o = output_params[idx].get_obj();
RPCTypeCheckObj(o,
{
@@ -2387,20 +2548,50 @@ UniValue lockunspent(const JSONRPCRequest& request)
{"vout", UniValueType(UniValue::VNUM)},
});
- std::string txid = find_value(o, "txid").get_str();
- if (!IsHex(txid))
+ const std::string& txid = find_value(o, "txid").get_str();
+ if (!IsHex(txid)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
+ }
- int nOutput = find_value(o, "vout").get_int();
- if (nOutput < 0)
+ const int nOutput = find_value(o, "vout").get_int();
+ if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
+ }
- COutPoint outpt(uint256S(txid), nOutput);
+ const COutPoint outpt(uint256S(txid), nOutput);
- if (fUnlock)
- pwallet->UnlockCoin(outpt);
- else
- pwallet->LockCoin(outpt);
+ const auto it = pwallet->mapWallet.find(outpt.hash);
+ if (it == pwallet->mapWallet.end()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
+ }
+
+ const CWalletTx& trans = it->second;
+
+ if (outpt.n >= trans.tx->vout.size()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
+ }
+
+ if (pwallet->IsSpent(outpt.hash, outpt.n)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
+ }
+
+ const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
+
+ if (fUnlock && !is_locked) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
+ }
+
+ if (!fUnlock && is_locked) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
+ }
+
+ outputs.push_back(outpt);
+ }
+
+ // Atomically set (un)locked status for the outputs.
+ for (const COutPoint& outpt : outputs) {
+ if (fUnlock) pwallet->UnlockCoin(outpt);
+ else pwallet->LockCoin(outpt);
}
return true;
@@ -2439,6 +2630,7 @@ UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listlockunspent", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::vector<COutPoint> vOutpts;
@@ -2517,6 +2709,12 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getwalletinfo", "")
);
+ ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
UniValue obj(UniValue::VOBJ);
@@ -2669,35 +2867,38 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
);
+ ObserveSafeMode();
+
int nMinDepth = 1;
- if (request.params.size() > 0 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
}
int nMaxDepth = 9999999;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
}
- std::set<CBitcoinAddress> setAddress;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ std::set<CTxDestination> destinations;
+ if (!request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
- CBitcoinAddress address(input.get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str());
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str());
- setAddress.insert(address);
+ CTxDestination dest = DecodeDestination(input.get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
+ }
+ if (!destinations.insert(dest).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
+ }
}
}
bool include_unsafe = true;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
include_unsafe = request.params[3].get_bool();
}
@@ -2723,9 +2924,12 @@ UniValue listunspent(const JSONRPCRequest& request)
nMaximumCount = options["maximumCount"].get_int64();
}
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
- assert(pwallet != nullptr);
LOCK2(cs_main, pwallet->cs_wallet);
pwallet->AvailableCoins(vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
@@ -2734,7 +2938,7 @@ UniValue listunspent(const JSONRPCRequest& request)
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
- if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
+ if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
UniValue entry(UniValue::VOBJ);
@@ -2742,7 +2946,7 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("vout", out.i));
if (fValidAddress) {
- entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
+ entry.push_back(Pair("address", EncodeDestination(address)));
if (pwallet->mapAddressBook.count(address)) {
entry.push_back(Pair("account", pwallet->mapAddressBook[address].name));
@@ -2797,7 +3001,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
- " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
+ " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
@@ -2830,8 +3034,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
+ ObserveSafeMode();
RPCTypeCheck(request.params, {UniValue::VSTR});
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
CCoinControl coinControl;
int changePosition = -1;
bool lockUnspents = false;
@@ -2864,12 +3073,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
true, true);
if (options.exists("changeAddress")) {
- CBitcoinAddress address(options["changeAddress"].get_str());
+ CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
- if (!address.IsValid())
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
+ }
- coinControl.destChange = address.Get();
+ coinControl.destChange = dest;
}
if (options.exists("changePosition"))
@@ -3041,48 +3251,57 @@ UniValue bumpfee(const JSONRPCRequest& request)
}
}
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- CFeeBumper feeBump(pwallet, hash, coin_control, totalFee);
- BumpFeeResult res = feeBump.getResult();
- if (res != BumpFeeResult::OK)
- {
+
+ std::vector<std::string> errors;
+ CAmount old_fee;
+ CAmount new_fee;
+ CMutableTransaction mtx;
+ feebumper::Result res = feebumper::CreateTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
+ if (res != feebumper::Result::OK) {
switch(res) {
- case BumpFeeResult::INVALID_ADDRESS_OR_KEY:
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_ADDRESS_OR_KEY:
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0]);
break;
- case BumpFeeResult::INVALID_REQUEST:
- throw JSONRPCError(RPC_INVALID_REQUEST, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_REQUEST:
+ throw JSONRPCError(RPC_INVALID_REQUEST, errors[0]);
break;
- case BumpFeeResult::INVALID_PARAMETER:
- throw JSONRPCError(RPC_INVALID_PARAMETER, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_PARAMETER:
+ throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0]);
break;
- case BumpFeeResult::WALLET_ERROR:
- throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ case feebumper::Result::WALLET_ERROR:
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
break;
default:
- throw JSONRPCError(RPC_MISC_ERROR, feeBump.getErrors()[0]);
+ throw JSONRPCError(RPC_MISC_ERROR, errors[0]);
break;
}
}
// sign bumped transaction
- if (!feeBump.signTransaction(pwallet)) {
+ if (!feebumper::SignTransaction(pwallet, mtx)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
}
// commit the bumped transaction
- if(!feeBump.commit(pwallet)) {
- throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ uint256 txid;
+ if (feebumper::CommitTransaction(pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
}
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("txid", feeBump.getBumpedTxId().GetHex()));
- result.push_back(Pair("origfee", ValueFromAmount(feeBump.getOldFee())));
- result.push_back(Pair("fee", ValueFromAmount(feeBump.getNewFee())));
- UniValue errors(UniValue::VARR);
- for (const std::string& err: feeBump.getErrors())
- errors.push_back(err);
- result.push_back(Pair("errors", errors));
+ result.push_back(Pair("txid", txid.GetHex()));
+ result.push_back(Pair("origfee", ValueFromAmount(old_fee)));
+ result.push_back(Pair("fee", ValueFromAmount(new_fee)));
+ UniValue result_errors(UniValue::VARR);
+ for (const std::string& error : errors) {
+ result_errors.push_back(error);
+ }
+ result.push_back(Pair("errors", result_errors));
return result;
}
@@ -3112,7 +3331,7 @@ UniValue generate(const JSONRPCRequest& request)
int num_generate = request.params[0].get_int();
uint64_t max_tries = 1000000;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
max_tries = request.params[1].get_int();
}
@@ -3132,6 +3351,81 @@ UniValue generate(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, num_generate, max_tries, true);
}
+UniValue rescanblockchain(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() > 2) {
+ throw std::runtime_error(
+ "rescanblockchain (\"start_height\") (\"stop_height\")\n"
+ "\nRescan the local blockchain for wallet related transactions.\n"
+ "\nArguments:\n"
+ "1. \"start_height\" (numeric, optional) block height where the rescan should start\n"
+ "2. \"stop_height\" (numeric, optional) the last block height that should be scanned\n"
+ "\nResult:\n"
+ "{\n"
+ " \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
+ " \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("rescanblockchain", "100000 120000")
+ + HelpExampleRpc("rescanblockchain", "100000, 120000")
+ );
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ CBlockIndex *pindexStart = chainActive.Genesis();
+ CBlockIndex *pindexStop = nullptr;
+ if (!request.params[0].isNull()) {
+ pindexStart = chainActive[request.params[0].get_int()];
+ if (!pindexStart) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
+ }
+ }
+
+ if (!request.params[1].isNull()) {
+ pindexStop = chainActive[request.params[1].get_int()];
+ if (!pindexStop) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
+ }
+ else if (pindexStop->nHeight < pindexStart->nHeight) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
+ }
+ }
+
+ // We can't rescan beyond non-pruned blocks, stop and throw an error
+ if (fPruneMode) {
+ CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
+ while (block && block->nHeight >= pindexStart->nHeight) {
+ if (!(block->nStatus & BLOCK_HAVE_DATA)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ }
+ block = block->pprev;
+ }
+ }
+
+ CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
+ if (!stopBlock) {
+ if (pwallet->IsAbortingRescan()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
+ }
+ // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
+ stopBlock = pindexStop ? pindexStop : chainActive.Tip();
+ }
+ else {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
+ }
+
+ UniValue response(UniValue::VOBJ);
+ response.pushKV("start_height", pindexStart->nHeight);
+ response.pushKV("stop_height", stopBlock->nHeight);
+ return response;
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -3142,69 +3436,68 @@ extern UniValue importwallet(const JSONRPCRequest& request);
extern UniValue importprunedfunds(const JSONRPCRequest& request);
extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
+extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
- { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} },
- { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} },
- { "wallet", "abortrescan", &abortrescan, false, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
- { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
- { "wallet", "backupwallet", &backupwallet, true, {"destination"} },
- { "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
- { "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
- { "wallet", "getaccountaddress", &getaccountaddress, true, {"account"} },
- { "wallet", "getaccount", &getaccount, true, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, {"account"} },
- { "wallet", "getbalance", &getbalance, false, {"account","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, true, {"account"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, {} },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, {"account","minconf"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, {"address","minconf"} },
- { "wallet", "gettransaction", &gettransaction, false, {"txid","include_watchonly"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, false, {} },
- { "wallet", "importmulti", &importmulti, true, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, true, {"filename"} },
- { "wallet", "importaddress", &importaddress, true, {"address","label","rescan","p2sh"} },
- { "wallet", "importprunedfunds", &importprunedfunds, true, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, true, {"pubkey","label","rescan"} },
- { "wallet", "keypoolrefill", &keypoolrefill, true, {"newsize"} },
- { "wallet", "listaccounts", &listaccounts, false, {"minconf","include_watchonly"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, {} },
- { "wallet", "listlockunspent", &listlockunspent, false, {} },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
- { "wallet", "listwallets", &listwallets, true, {} },
- { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
- { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
- { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
- { "wallet", "setaccount", &setaccount, true, {"address","account"} },
- { "wallet", "settxfee", &settxfee, true, {"amount"} },
- { "wallet", "signmessage", &signmessage, true, {"address","message"} },
- { "wallet", "walletlock", &walletlock, true, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} },
-
- { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
+ { "wallet", "backupwallet", &backupwallet, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
+ { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
+ { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
+ { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
+ { "wallet", "getaccount", &getaccount, {"address"} },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
+ { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"account"} },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, {} },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importmulti", &importmulti, {"requests","options"} },
+ { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
+ { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
+ { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
+ { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlockunspent", &listlockunspent, {} },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
+ { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
+ { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
+ { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
+ { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "setaccount", &setaccount, {"address","account"} },
+ { "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "signmessage", &signmessage, {"address","message"} },
+ { "wallet", "walletlock", &walletlock, {} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+ { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
+
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
{
- if (gArgs.GetBoolArg("-disablewallet", false))
- return;
-
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index db0808b93b..14e51610d9 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -5,7 +5,10 @@
#ifndef BITCOIN_WALLET_RPCWALLET_H
#define BITCOIN_WALLET_RPCWALLET_H
+#include <string>
+
class CRPCTable;
+class CWallet;
class JSONRPCRequest;
void RegisterWalletRPCCommands(CRPCTable &t);
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index 330878ceb5..b95bb14335 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -2,26 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
-#include "wallet/test/wallet_test_fixture.h"
+#include <wallet/test/wallet_test_fixture.h>
#include <stdint.h>
#include <boost/test/unit_test.hpp>
-extern CWallet* pwalletMain;
-
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
static void
-GetResults(std::map<CAmount, CAccountingEntry>& results)
+GetResults(CWallet *wallet, std::map<CAmount, CAccountingEntry>& results)
{
std::list<CAccountingEntry> aes;
results.clear();
- BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);
- pwalletMain->ListAccountCreditDebit("", aes);
+ BOOST_CHECK(wallet->ReorderTransactions() == DB_LOAD_OK);
+ wallet->ListAccountCreditDebit("", aes);
for (CAccountingEntry& ae : aes)
{
results[ae.nOrderPos] = ae;
@@ -54,7 +52,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.strOtherAccount = "c";
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
BOOST_CHECK(2 == results.size());
@@ -70,7 +68,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nOrderPos = pwalletMain->IncOrderPosNext();
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
@@ -83,7 +81,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "y";
{
- CMutableTransaction tx(wtx);
+ CMutableTransaction tx(*wtx.tx);
--tx.nLockTime; // Just to change the hash :)
wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
@@ -93,7 +91,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "x";
{
- CMutableTransaction tx(wtx);
+ CMutableTransaction tx(*wtx.tx);
--tx.nLockTime; // Just to change the hash :)
wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
@@ -102,7 +100,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1;
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
@@ -120,7 +118,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nOrderPos = -1;
pwalletMain->AddAccountingEntry(ae);
- GetResults(results);
+ GetResults(pwalletMain.get(), results);
BOOST_CHECK(results.size() == 4);
BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index 98d957b322..3ff8c6d224 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -2,93 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "test/test_bitcoin.h"
-#include "utilstrencodings.h"
-#include "wallet/crypter.h"
+#include <test/test_bitcoin.h>
+#include <utilstrencodings.h>
+#include <wallet/crypter.h>
#include <vector>
#include <boost/test/unit_test.hpp>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)
-bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)
-{
- if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
- return false;
-
- int i = 0;
- if (nDerivationMethod == 0)
- i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
- (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
-
- if (i != (int)WALLET_CRYPTO_KEY_SIZE)
- {
- memory_cleanse(chKey, WALLET_CRYPTO_KEY_SIZE);
- memory_cleanse(chIV, WALLET_CRYPTO_IV_SIZE);
- return false;
- }
- return true;
-}
-
-bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // max ciphertext len for a n bytes of plaintext is
- // n + AES_BLOCK_SIZE - 1 bytes
- int nLen = vchPlaintext.size();
- int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
- vchCiphertext = std::vector<unsigned char> (nCLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, chKey, chIV) != 0;
- if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
- if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchCiphertext.resize(nCLen + nFLen);
- return true;
-}
-
-bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // plaintext will always be equal to or lesser than length of ciphertext
- int nLen = vchCiphertext.size();
- int nPLen = nLen, nFLen = 0;
-
- vchPlaintext = CKeyingMaterial(nPLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, chKey, chIV) != 0;
- if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
- if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchPlaintext.resize(nPLen + nFLen);
- return true;
-}
-
class TestCrypter
{
public:
@@ -96,25 +19,15 @@ static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, cons
const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
{
- unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
- unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
-
CCrypter crypt;
crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);
- OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
-
- BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.vchKey));
- BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, \
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.vchIV));
-
if(!correctKey.empty())
- BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correctKey.data(), crypt.vchKey.size()) == 0, \
+ HexStr(crypt.vchKey.begin(), crypt.vchKey.end()) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
if(!correctIV.empty())
- BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correctIV.data(), crypt.vchIV.size()) == 0,
+ HexStr(crypt.vchIV.begin(), crypt.vchIV.end()) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
}
static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
@@ -126,50 +39,26 @@ static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const Secu
TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);
}
-
static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \
const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())
{
- CKeyingMaterial vchDecrypted1;
- CKeyingMaterial vchDecrypted2;
- int result1, result2;
- result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
- result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
-
- // These two should be equal. However, OpenSSL 1.0.1j introduced a change
- // that would zero all padding except for the last byte for failed decrypts.
- // This behavior was reverted for 1.0.1k.
- if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)
- {
- for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)
- *it = 0;
- }
-
- BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));
-
+ CKeyingMaterial vchDecrypted;
+ crypt.Decrypt(vchCiphertext, vchDecrypted);
if (vchPlaintext.size())
- BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);
+ BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted);
}
static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,
const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
{
- std::vector<unsigned char> vchCiphertext1;
- std::vector<unsigned char> vchCiphertext2;
- int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
-
- int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
- BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
+ std::vector<unsigned char> vchCiphertext;
+ crypt.Encrypt(vchPlaintext, vchCiphertext);
if (!vchCiphertextCorrect.empty())
- BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);
+ BOOST_CHECK(vchCiphertext == vchCiphertextCorrect);
const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());
-
- if(vchCiphertext1 == vchCiphertext2)
- TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);
+ TestDecrypt(crypt, vchCiphertext, vchPlaintext2);
}
static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \
@@ -191,7 +80,7 @@ BOOST_AUTO_TEST_CASE(passphrase) {
std::string hash(GetRandHash().ToString());
std::vector<unsigned char> vchSalt(8);
- GetRandBytes(&vchSalt[0], vchSalt.size());
+ GetRandBytes(vchSalt.data(), vchSalt.size());
uint32_t rounds = InsecureRand32();
if (rounds > 30000)
rounds = 30000;
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index e2f48c45ab..3ee83d2d7c 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -2,13 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/test/wallet_test_fixture.h"
+#include <wallet/test/wallet_test_fixture.h>
-#include "rpc/server.h"
-#include "wallet/db.h"
-#include "wallet/wallet.h"
-
-CWallet *pwalletMain;
+#include <rpc/server.h>
+#include <wallet/db.h>
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName)
@@ -17,18 +14,16 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
bool fFirstRun;
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
- pwalletMain = new CWallet(std::move(dbw));
+ pwalletMain = MakeUnique<CWallet>(std::move(dbw));
pwalletMain->LoadWallet(fFirstRun);
- RegisterValidationInterface(pwalletMain);
+ RegisterValidationInterface(pwalletMain.get());
RegisterWalletRPCCommands(tableRPC);
}
WalletTestingSetup::~WalletTestingSetup()
{
- UnregisterValidationInterface(pwalletMain);
- delete pwalletMain;
- pwalletMain = nullptr;
+ UnregisterValidationInterface(pwalletMain.get());
bitdb.Flush(true);
bitdb.Reset();
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 97a6d98397..292d654438 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -5,13 +5,17 @@
#ifndef BITCOIN_WALLET_TEST_FIXTURE_H
#define BITCOIN_WALLET_TEST_FIXTURE_H
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
+
+#include <wallet/wallet.h>
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup: public TestingSetup {
- WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
+
+ std::unique_ptr<CWallet> pwalletMain;
};
#endif
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 4a2cc9a139..80e31a1ce0 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -2,25 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#include <set>
#include <stdint.h>
#include <utility>
#include <vector>
-#include "consensus/validation.h"
-#include "rpc/server.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "wallet/coincontrol.h"
-#include "wallet/test/wallet_test_fixture.h"
+#include <consensus/validation.h>
+#include <rpc/server.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
-extern CWallet* pwalletMain;
-
extern UniValue importmulti(const JSONRPCRequest& request);
extern UniValue dumpwallet(const JSONRPCRequest& request);
extern UniValue importwallet(const JSONRPCRequest& request);
@@ -364,6 +362,12 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
empty_wallet();
}
+static void AddKey(CWallet& wallet, const CKey& key)
+{
+ LOCK(wallet.cs_wallet);
+ wallet.AddKeyPubKey(key, key.GetPubKey());
+}
+
BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
LOCK(cs_main);
@@ -379,9 +383,8 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// and new block files.
{
CWallet wallet;
- LOCK(wallet.cs_wallet);
- wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
- BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));
+ AddKey(wallet, coinbaseKey);
+ BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -393,9 +396,8 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// file.
{
CWallet wallet;
- LOCK(wallet.cs_wallet);
- wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
- BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
+ AddKey(wallet, coinbaseKey);
+ BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -485,6 +487,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
vpwallets[0] = &wallet;
::importwallet(request);
+ LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103);
for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
@@ -530,6 +533,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
if (blockTime > 0) {
+ LOCK(cs_main);
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash = inserted.first->first;
@@ -543,6 +547,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
wtx.SetMerkleBranch(block, 0);
}
wallet.AddToWallet(wtx);
+ LOCK(wallet.cs_wallet);
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
}
@@ -579,6 +584,7 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
{
CTxDestination dest = CKeyID();
+ LOCK(pwalletMain->cs_wallet);
pwalletMain->AddDestData(dest, "misc", "val_misc");
pwalletMain->AddDestData(dest, "rr0", "val_rr0");
pwalletMain->AddDestData(dest, "rr1", "val_rr1");
@@ -599,9 +605,8 @@ public:
wallet.reset(new CWallet(std::unique_ptr<CWalletDBWrapper>(new CWalletDBWrapper(&bitdb, "wallet_test.dat"))));
bool firstRun;
wallet->LoadWallet(firstRun);
- LOCK(wallet->cs_wallet);
- wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
- wallet->ScanForWalletTransactions(chainActive.Genesis());
+ AddKey(*wallet, coinbaseKey);
+ wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr);
}
~ListCoinsTestingSetup()
@@ -622,6 +627,7 @@ public:
BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
+ LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(wtx.GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
@@ -635,7 +641,7 @@ public:
BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
- LOCK(wallet->cs_wallet);
+ LOCK2(cs_main, wallet->cs_wallet);
// Confirm ListCoins initially returns 1 coin grouped under coinbaseKey
// address.
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 1afabd6099..dafd708d09 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3,35 +3,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
-
-#include "base58.h"
-#include "checkpoints.h"
-#include "chain.h"
-#include "wallet/coincontrol.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "init.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sign.h"
-#include "scheduler.h"
-#include "timedata.h"
-#include "txmempool.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "utilmoneystr.h"
+#include <wallet/wallet.h>
+
+#include <base58.h>
+#include <checkpoints.h>
+#include <chain.h>
+#include <wallet/coincontrol.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <wallet/init.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <scheduler.h>
+#include <timedata.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <wallet/fees.h>
#include <assert.h>
+#include <future>
#include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp>
@@ -110,7 +110,26 @@ public:
Process(script);
}
- void operator()(const CNoDestination &none) {}
+ void operator()(const WitnessV0ScriptHash& scriptID)
+ {
+ CScriptID id;
+ CRIPEMD160().Write(scriptID.begin(), 32).Finalize(id.begin());
+ CScript script;
+ if (keystore.GetCScript(id, script)) {
+ Process(script);
+ }
+ }
+
+ void operator()(const WitnessV0KeyHash& keyid)
+ {
+ CKeyID id(keyid);
+ if (keystore.HaveKey(id)) {
+ vKeys.push_back(id);
+ }
+ }
+
+ template<typename X>
+ void operator()(const X &none) {}
};
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
@@ -263,7 +282,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
}
}
-bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta)
+bool CWallet::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
UpdateTimeFirstKey(meta.nCreateTime);
@@ -271,6 +290,14 @@ bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &m
return true;
}
+bool CWallet::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &meta)
+{
+ AssertLockHeld(cs_wallet); // m_script_metadata
+ UpdateTimeFirstKey(meta.nCreateTime);
+ m_script_metadata[script_id] = meta;
+ return true;
+}
+
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
@@ -306,7 +333,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
- std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString();
+ std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
@@ -319,7 +346,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
- const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
+ const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime);
NotifyWatchonlyChanged(true);
return CWalletDB(*dbw).WriteWatchOnly(dest, meta);
@@ -327,7 +354,7 @@ bool CWallet::AddWatchOnly(const CScript& dest)
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
{
- mapKeyMetadata[CScriptID(dest)].nCreateTime = nCreateTime;
+ m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime;
return AddWatchOnly(dest);
}
@@ -389,11 +416,11 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
+ pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+ pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
@@ -494,63 +521,6 @@ void CWallet::Flush(bool shutdown)
dbw->Flush(shutdown);
}
-bool CWallet::Verify()
-{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- uiInterface.InitMessage(_("Verifying wallet(s)..."));
-
- // Keep track of each wallet absolute path to detect duplicates.
- std::set<fs::path> wallet_paths;
-
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- if (boost::filesystem::path(walletFile).filename() != walletFile) {
- return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
- }
-
- if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
- return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile));
- }
-
- fs::path wallet_path = fs::absolute(walletFile, GetDataDir());
-
- if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
- return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile));
- }
-
- if (!wallet_paths.insert(wallet_path).second) {
- return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
- }
-
- std::string strError;
- if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
- return InitError(strError);
- }
-
- if (gArgs.GetBoolArg("-salvagewallet", false)) {
- // Recover readable keypairs:
- CWallet dummyWallet;
- std::string backup_filename;
- if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
- return false;
- }
- }
-
- std::string strWarning;
- bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
- if (!strWarning.empty()) {
- InitWarning(strWarning);
- }
- if (!dbV) {
- InitError(strError);
- return false;
- }
- }
-
- return true;
-}
-
void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
{
// We want all the wallet transactions in range to have the same metadata as
@@ -569,12 +539,16 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
copyFrom = &mapWallet[hash];
}
}
+
+ assert(copyFrom);
+
// Now copy data from copyFrom to rest:
for (TxSpends::iterator it = range.first; it != range.second; ++it)
{
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
@@ -623,8 +597,9 @@ void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
void CWallet::AddToSpends(const uint256& wtxid)
{
- assert(mapWallet.count(wtxid));
- CWalletTx& thisTx = mapWallet[wtxid];
+ auto it = mapWallet.find(wtxid);
+ assert(it != mapWallet.end());
+ CWalletTx& thisTx = it->second;
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
@@ -650,11 +625,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
+ kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+ kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
@@ -736,16 +711,16 @@ DBErrors CWallet::ReorderTransactions()
typedef std::multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
- for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (auto& entry : mapWallet)
{
- CWalletTx* wtx = &((*it).second);
- txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
+ CWalletTx* wtx = &entry.second;
+ txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr)));
}
std::list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit("", acentries);
for (CAccountingEntry& entry : acentries)
{
- txByTime.insert(std::make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ txByTime.insert(std::make_pair(entry.nTime, TxPair(nullptr, &entry)));
}
nOrderPosNext = 0;
@@ -754,7 +729,7 @@ DBErrors CWallet::ReorderTransactions()
{
CWalletTx *const pwtx = (*it).second.first;
CAccountingEntry *const pacentry = (*it).second.second;
- int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
+ int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos;
if (nOrderPos == -1)
{
@@ -939,7 +914,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb);
- wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
}
@@ -969,6 +944,15 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
+ // If we have a witness-stripped version of this transaction, and we
+ // see a new version with a witness, then we must be upgrading a pre-segwit
+ // wallet. Store the new version of the transaction with the witness,
+ // as the stripped-version must be invalid.
+ // TODO: Store all versions of the transaction, instead of just one.
+ if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
+ wtx.SetTx(wtxIn.tx);
+ fUpdated = true;
+ }
}
//// debug print
@@ -988,7 +972,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
// notify an external script when a wallet transaction comes in or is updated
std::string strCmd = gArgs.GetArg("-walletnotify", "");
- if ( !strCmd.empty())
+ if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
@@ -1004,11 +988,12 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
mapWallet[hash] = wtxIn;
CWalletTx& wtx = mapWallet[hash];
wtx.BindWallet(this);
- wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
AddToSpends(hash);
for (const CTxIn& txin : wtx.tx->vin) {
- if (mapWallet.count(txin.prevout.hash)) {
- CWalletTx& prevtx = mapWallet[txin.prevout.hash];
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ CWalletTx& prevtx = it->second;
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
@@ -1107,8 +1092,9 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
std::set<uint256> done;
// Can't mark abandoned if confirmed or in mempool
- assert(mapWallet.count(hashTx));
- CWalletTx& origtx = mapWallet[hashTx];
+ auto it = mapWallet.find(hashTx);
+ assert(it != mapWallet.end());
+ CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
return false;
}
@@ -1119,8 +1105,9 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
@@ -1145,8 +1132,10 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
// available of the outputs it spends. So force those to be recomputed
for (const CTxIn& txin : wtx.tx->vin)
{
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
@@ -1184,8 +1173,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
@@ -1204,10 +1194,11 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
- for (const CTxIn& txin : wtx.tx->vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : wtx.tx->vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
@@ -1222,16 +1213,30 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
- for (const CTxIn& txin : tx.vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : tx.vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
LOCK2(cs_main, cs_wallet);
SyncTransaction(ptx);
+
+ auto it = mapWallet.find(ptx->GetHash());
+ if (it != mapWallet.end()) {
+ it->second.fInMempool = true;
+ }
+}
+
+void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
+ LOCK(cs_wallet);
+ auto it = mapWallet.find(ptx->GetHash());
+ if (it != mapWallet.end()) {
+ it->second.fInMempool = false;
+ }
}
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
@@ -1246,10 +1251,14 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
for (const CTransactionRef& ptx : vtxConflicted) {
SyncTransaction(ptx);
+ TransactionRemovedFromMempool(ptx);
}
for (size_t i = 0; i < pblock->vtx.size(); i++) {
SyncTransaction(pblock->vtx[i], pindex, i);
+ TransactionRemovedFromMempool(pblock->vtx[i]);
}
+
+ m_last_block_processed = pindex;
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@@ -1262,6 +1271,36 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
+void CWallet::BlockUntilSyncedToCurrentChain() {
+ AssertLockNotHeld(cs_main);
+ AssertLockNotHeld(cs_wallet);
+
+ {
+ // Skip the queue-draining stuff if we know we're caught up with
+ // chainActive.Tip()...
+ // We could also take cs_wallet here, and call m_last_block_processed
+ // protected by cs_wallet instead of cs_main, but as long as we need
+ // cs_main here anyway, its easier to just call it cs_main-protected.
+ LOCK(cs_main);
+ const CBlockIndex* initialChainTip = chainActive.Tip();
+
+ if (m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ return;
+ }
+ }
+
+ // ...otherwise put a callback in the validation interface queue and wait
+ // for the queue to drain enough to execute it (indicating we are caught up
+ // at least with the time we entered this function).
+
+ std::promise<void> promise;
+ CallFunctionInValidationInterfaceQueue([&promise] {
+ promise.set_value();
+ });
+ promise.get_future().wait();
+}
+
+
isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
@@ -1586,7 +1625,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
if (startBlock) {
- const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);
+ const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update);
if (failedBlock) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
}
@@ -1602,12 +1641,19 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
* Returns null if scan was successful. Otherwise, if a complete rescan was not
* possible (due to pruning or corruption), returns pointer to the most recent
* block that could not be scanned.
+ *
+ * If pindexStop is not a nullptr, the scan will stop at the block-index
+ * defined by pindexStop
*/
-CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
+CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
{
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
+ if (pindexStop) {
+ assert(pindexStop->nHeight >= pindexStart->nHeight);
+ }
+
CBlockIndex* pindex = pindexStart;
CBlockIndex* ret = nullptr;
{
@@ -1635,6 +1681,9 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
} else {
ret = pindex;
}
+ if (pindex == pindexStop) {
+ break;
+ }
pindex = chainActive.Next(pindex);
}
if (pindex && fAbortRescan) {
@@ -1670,11 +1719,8 @@ void CWallet::ReacceptWalletTransactions()
}
// Try to add wallet transactions to memory pool
- for (std::pair<const int64_t, CWalletTx*>& item : mapSorted)
- {
+ for (std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second);
-
- LOCK(mempool.cs);
CValidationState state;
wtx.AcceptToMemoryPool(maxTxFee, state);
}
@@ -1726,7 +1772,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
debit += nDebitCached;
else
{
- nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
+ nDebitCached = pwallet->GetDebit(*tx, ISMINE_SPENDABLE);
fDebitCached = true;
debit += nDebitCached;
}
@@ -1737,7 +1783,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
debit += nWatchDebitCached;
else
{
- nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
+ nWatchDebitCached = pwallet->GetDebit(*tx, ISMINE_WATCH_ONLY);
fWatchDebitCached = true;
debit += nWatchDebitCached;
}
@@ -1759,7 +1805,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
credit += nCreditCached;
else
{
- nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
+ nCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
fCreditCached = true;
credit += nCreditCached;
}
@@ -1770,7 +1816,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
credit += nWatchCreditCached;
else
{
- nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ nWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
fWatchCreditCached = true;
credit += nWatchCreditCached;
}
@@ -1784,7 +1830,7 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
- nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
+ nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
fImmatureCreditCached = true;
return nImmatureCreditCached;
}
@@ -1794,7 +1840,7 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
{
- if (pwallet == 0)
+ if (pwallet == nullptr)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
@@ -1828,7 +1874,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
{
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
- nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
fImmatureWatchCreditCached = true;
return nImmatureWatchCreditCached;
}
@@ -1838,7 +1884,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool fUseCache) const
{
- if (pwallet == 0)
+ if (pwallet == nullptr)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
@@ -1869,21 +1915,20 @@ CAmount CWalletTx::GetChange() const
{
if (fChangeCached)
return nChangeCached;
- nChangeCached = pwallet->GetChange(*this);
+ nChangeCached = pwallet->GetChange(*tx);
fChangeCached = true;
return nChangeCached;
}
bool CWalletTx::InMempool() const
{
- LOCK(mempool.cs);
- return mempool.exists(GetHash());
+ return fInMempool;
}
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
- if (!CheckFinalTx(*this))
+ if (!CheckFinalTx(*tx))
return false;
int nDepth = GetDepthInMainChain();
if (nDepth >= 1)
@@ -1984,9 +2029,9 @@ CAmount CWallet::GetBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
@@ -2000,9 +2045,9 @@ CAmount CWallet::GetUnconfirmedBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
@@ -2015,9 +2060,9 @@ CAmount CWallet::GetImmatureBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
nTotal += pcoin->GetImmatureCredit();
}
}
@@ -2029,9 +2074,9 @@ CAmount CWallet::GetWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
@@ -2045,9 +2090,9 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
@@ -2060,9 +2105,9 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &(*it).second;
+ const CWalletTx* pcoin = &entry.second;
nTotal += pcoin->GetImmatureWatchOnlyCredit();
}
}
@@ -2136,12 +2181,12 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
CAmount nTotal = 0;
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (const auto& entry : mapWallet)
{
- const uint256& wtxid = it->first;
- const CWalletTx* pcoin = &(*it).second;
+ const uint256& wtxid = entry.first;
+ const CWalletTx* pcoin = &entry.second;
- if (!CheckFinalTx(*pcoin))
+ if (!CheckFinalTx(*pcoin->tx))
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -2200,10 +2245,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
continue;
- if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint((*it).first, i)))
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i)))
continue;
- if (IsLockedCoin((*it).first, i))
+ if (IsLockedCoin(entry.first, i))
continue;
if (IsSpent(wtxid, i))
@@ -2550,9 +2595,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
{
std::vector<CRecipient> vecSend;
- // Turn the txout set into a CRecipient vector
- for (size_t idx = 0; idx < tx.vout.size(); idx++)
- {
+ // Turn the txout set into a CRecipient vector.
+ for (size_t idx = 0; idx < tx.vout.size(); idx++) {
const CTxOut& txOut = tx.vout[idx];
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1};
vecSend.push_back(recipient);
@@ -2560,8 +2604,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
coinControl.fAllowOtherInputs = true;
- for (const CTxIn& txin : tx.vin)
+ for (const CTxIn& txin : tx.vin) {
coinControl.Select(txin.prevout);
+ }
+
+ // Acquire the locks to prevent races to the new locked unspents between the
+ // CreateTransaction call and LockCoin calls (when lockUnspents is true).
+ LOCK2(cs_main, cs_wallet);
CReserveKey reservekey(this);
CWalletTx wtx;
@@ -2571,45 +2620,31 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
if (nChangePosInOut != -1) {
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
- // we dont have the normal Create/Commit cycle, and dont want to risk reusing change,
- // so just remove the key from the keypool here.
+ // We don't have the normal Create/Commit cycle, and don't want to risk
+ // reusing change, so just remove the key from the keypool here.
reservekey.KeepKey();
}
- // Copy output sizes from new transaction; they may have had the fee subtracted from them
- for (unsigned int idx = 0; idx < tx.vout.size(); idx++)
+ // Copy output sizes from new transaction; they may have had the fee
+ // subtracted from them.
+ for (unsigned int idx = 0; idx < tx.vout.size(); idx++) {
tx.vout[idx].nValue = wtx.tx->vout[idx].nValue;
+ }
- // Add new txins (keeping original txin scriptSig/order)
- for (const CTxIn& txin : wtx.tx->vin)
- {
- if (!coinControl.IsSelected(txin.prevout))
- {
+ // Add new txins while keeping original txin scriptSig/order.
+ for (const CTxIn& txin : wtx.tx->vin) {
+ if (!coinControl.IsSelected(txin.prevout)) {
tx.vin.push_back(txin);
- if (lockUnspents)
- {
- LOCK2(cs_main, cs_wallet);
- LockCoin(txin.prevout);
+ if (lockUnspents) {
+ LockCoin(txin.prevout);
}
}
}
-
return true;
}
-static CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
-{
- unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
- CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
- // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
- discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
- // Discard rate must be at least dustRelayFee
- discard_rate = std::max(discard_rate, ::dustRelayFee);
- return discard_rate;
-}
-
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
@@ -2670,6 +2705,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
FeeCalculation feeCalc;
+ CAmount nFeeNeeded;
unsigned int nBytes;
{
std::set<CInputCoin> setCoins;
@@ -2732,6 +2768,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (recipient.fSubtractFeeFromAmount)
{
+ assert(nSubtractFeeFromAmount != 0);
txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
if (fFirst) // first receiver pays the remainder not divisible by output count
@@ -2831,7 +2868,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
vin.scriptWitness.SetNull();
}
- CAmount nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
+ nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@@ -2852,13 +2889,15 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
- CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, coin_control, ::mempool, ::feeEstimator, nullptr);
- CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
- CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
- if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
- pick_new_inputs = false;
- nFeeRet = nFeeNeeded + fee_needed_for_change;
- continue;
+ if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
+ unsigned int tx_size_with_change = nBytes + change_prototype_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size
+ CAmount fee_needed_with_change = GetMinimumFee(tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr);
+ CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
+ if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) {
+ pick_new_inputs = false;
+ nFeeRet = fee_needed_with_change;
+ continue;
+ }
}
// If we have change output already, just increase it
@@ -2930,7 +2969,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));
// Limit size
- if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)
+ if (GetTransactionWeight(*wtxNew.tx) >= MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large");
return false;
@@ -2953,8 +2992,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
- LogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
- nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
+ LogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
+ nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool),
feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
@@ -2992,14 +3031,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
+ // Get the inserted-CWalletTx from mapWallet so that the
+ // fInMempool flag is cached properly
+ CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
+
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {
+ if (!wtx.AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
- wtxNew.RelayWalletTransaction(connman);
+ wtx.RelayWalletTransaction(connman);
}
}
}
@@ -3026,85 +3069,21 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwa
laccentries.push_back(acentry);
CAccountingEntry & entry = laccentries.back();
- wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
+ wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair(nullptr, &entry)));
return true;
}
-CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
-{
- return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
-}
-
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
-{
- /* User control of how to calculate fee uses the following parameter precedence:
- 1. coin_control.m_feerate
- 2. coin_control.m_confirm_target
- 3. payTxFee (user-set global variable)
- 4. nTxConfirmTarget (user-set global variable)
- The first parameter that is set is used.
- */
- CAmount fee_needed;
- if (coin_control.m_feerate) { // 1.
- fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
- // Allow to override automatic min/max check over coin control instance
- if (coin_control.fOverrideFeeRate) return fee_needed;
- }
- else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
- fee_needed = ::payTxFee.GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
- }
- else { // 2. or 4.
- // We will use smart fee estimation
- unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
- // By default estimates are economical iff we are signaling opt-in-RBF
- bool conservative_estimate = !coin_control.signalRbf;
- // Allow to override the default fee estimate mode over the CoinControl instance
- if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
- else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
-
- fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
- if (fee_needed == 0) {
- // if we don't have enough data for estimateSmartFee, then use fallbackFee
- fee_needed = fallbackFee.GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
- }
- // Obey mempool min fee when using smart fee estimation
- CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
- if (fee_needed < min_mempool_fee) {
- fee_needed = min_mempool_fee;
- if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
- }
- }
-
- // prevent user from paying a fee below minRelayTxFee or minTxFee
- CAmount required_fee = GetRequiredFee(nTxBytes);
- if (required_fee > fee_needed) {
- fee_needed = required_fee;
- if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
- }
- // But always obey the maximum
- if (fee_needed > maxTxFee) {
- fee_needed = maxTxFee;
- if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
- }
- return fee_needed;
-}
-
-
-
-
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
+ LOCK2(cs_main, cs_wallet);
+
fFirstRunRet = false;
DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE)
{
if (dbw->Rewrite("\x04pool"))
{
- LOCK(cs_wallet);
setInternalKeyPool.clear();
setExternalKeyPool.clear();
m_pool_key_to_index.clear();
@@ -3114,9 +3093,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
}
+ // This wallet is in its first run if all of these are empty
+ fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
+
if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
- fFirstRunRet = !vchDefaultKey.IsValid();
uiInterface.LoadWallet(this);
@@ -3126,7 +3107,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
AssertLockHeld(cs_wallet); // mapWallet
- vchDefaultKey = CPubKey();
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut)
mapWallet.erase(hash);
@@ -3155,7 +3135,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
- vchDefaultKey = CPubKey();
DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
@@ -3191,9 +3170,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
- if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
+ if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose))
return false;
- return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
+ return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@@ -3202,7 +3181,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
LOCK(cs_wallet); // mapAddressBook
// Delete destdata tuples associated with address
- std::string strAddress = CBitcoinAddress(address).ToString();
+ std::string strAddress = EncodeDestination(address);
for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata)
{
CWalletDB(*dbw).EraseDestData(strAddress, item.first);
@@ -3212,8 +3191,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
- CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString());
- return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
+ CWalletDB(*dbw).ErasePurpose(EncodeDestination(address));
+ return CWalletDB(*dbw).EraseName(EncodeDestination(address));
}
const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
@@ -3231,14 +3210,6 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
return DEFAULT_ACCOUNT_NAME;
}
-bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
-{
- if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
- return false;
- vchDefaultKey = vchPubKey;
- return true;
-}
-
/**
* Mark old keypool keys as used,
* and generate all new keys
@@ -3659,15 +3630,11 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
}
walletdb.ErasePool(index);
+ LogPrintf("keypool index %d removed\n", index);
it = setKeyPool->erase(it);
}
}
-bool CWallet::HasUnusedKeys(int min_keys) const
-{
- return setExternalKeyPool.size() >= min_keys && (setInternalKeyPool.size() >= min_keys || !CanSupportFeature(FEATURE_HD_SPLIT));
-}
-
void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script)
{
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this);
@@ -3731,13 +3698,10 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
// map in which we'll infer heights of other keys
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
- std::set<CKeyID> setKeys;
- GetKeys(setKeys);
- for (const CKeyID &keyid : setKeys) {
+ for (const CKeyID &keyid : GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = pindexMax;
}
- setKeys.clear();
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
@@ -3745,9 +3709,9 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
- for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
+ for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
- const CWalletTx &wtx = (*it).second;
+ const CWalletTx &wtx = entry.second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
@@ -3767,8 +3731,8 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
}
// Extract block timestamps for those keys
- for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+ for (const auto& entry : mapKeyFirstBlock)
+ mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
}
/**
@@ -3842,14 +3806,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
return false;
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
- return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
+ return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value);
}
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
{
if (!mapAddressBook[dest].destdata.erase(key))
return false;
- return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key);
+ return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3888,46 +3852,6 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
-std::string CWallet::GetWalletHelpString(bool showDebug)
-{
- std::string strUsage = HelpMessageGroup(_("Wallet options:"));
- strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
- strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
- strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
- strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
- "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
- CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
- strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
- strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
- strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
- strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
- strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
- strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
- strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
- strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
- strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
- strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
- strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
- " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
- if (showDebug)
- {
- strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
-
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
- strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
- strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
- strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
- }
-
- return strUsage;
-}
-
CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
{
// needed to restore wallet transaction meta data after -zapwallettxes
@@ -3937,15 +3861,12 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
- CWallet *tempWallet = new CWallet(std::move(dbw));
+ std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(std::move(dbw));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
return nullptr;
}
-
- delete tempWallet;
- tempWallet = nullptr;
}
uiInterface.InitMessage(_("Loading wallet..."));
@@ -4003,30 +3924,28 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (fFirstRun)
{
- // Create new keyUser and set as default key
- if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
+ // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
+ if (!gArgs.GetBoolArg("-usehd", true)) {
+ InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile));
+ return nullptr;
+ }
+ walletInstance->SetMinVersion(FEATURE_NO_DEFAULT_KEY);
- // 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");
- // 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, false)) {
- walletInstance->SetDefaultKey(newDefaultKey);
- if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
- InitError(_("Cannot write default address") += "\n");
- return nullptr;
- }
+ // Top up the keypool
+ if (!walletInstance->TopUpKeyPool()) {
+ InitError(_("Unable to generate initial keys") += "\n");
+ return nullptr;
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
else if (gArgs.IsArgSet("-usehd")) {
- bool useHD = gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
+ bool useHD = gArgs.GetBoolArg("-usehd", true);
if (walletInstance->IsHDEnabled() && !useHD) {
InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile));
return nullptr;
@@ -4039,8 +3958,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
- RegisterValidationInterface(walletInstance);
-
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
@@ -4052,6 +3969,10 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
}
+
+ walletInstance->m_last_block_processed = chainActive.Tip();
+ RegisterValidationInterface(walletInstance);
+
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
@@ -4079,7 +4000,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}
nStart = GetTimeMillis();
- walletInstance->ScanForWalletTransactions(pindexRescan, true);
+ walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
walletInstance->dbw->IncrementUpdateCounter();
@@ -4121,24 +4042,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
return walletInstance;
}
-bool CWallet::InitLoadWallet()
-{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- LogPrintf("Wallet disabled!\n");
- return true;
- }
-
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- CWallet * const pwallet = CreateWalletFromFile(walletFile);
- if (!pwallet) {
- return false;
- }
- vpwallets.push_back(pwallet);
- }
-
- return true;
-}
-
std::atomic<bool> CWallet::fFlushScheduled(false);
void CWallet::postInitProcess(CScheduler& scheduler)
@@ -4153,126 +4056,6 @@ void CWallet::postInitProcess(CScheduler& scheduler)
}
}
-bool CWallet::ParameterInteraction()
-{
- gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
- const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
-
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
- }
-
- if (gArgs.GetBoolArg("-salvagewallet", false)) {
- if (is_multiwallet) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
- }
- // Rewrite just private keys: rescan to find transactions
- if (gArgs.SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
- }
- }
-
- int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
- // -zapwallettxes implies dropping the mempool on startup
- if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
- }
-
- // -zapwallettxes implies a rescan
- if (zapwallettxes != 0) {
- if (is_multiwallet) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
- }
- if (gArgs.SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
- }
- }
-
- if (is_multiwallet) {
- if (gArgs.GetBoolArg("-upgradewallet", false)) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
- }
- }
-
- if (gArgs.GetBoolArg("-sysperms", false))
- return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
- if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
- return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
-
- if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
- _("The wallet will avoid paying less than the minimum relay fee."));
-
- if (gArgs.IsArgSet("-mintxfee"))
- {
- CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
- return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
- if (n > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-mintxfee") + " " +
- _("This is the minimum transaction fee you pay on every transaction."));
- CWallet::minTxFee = CFeeRate(n);
- }
- if (gArgs.IsArgSet("-fallbackfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
- return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-fallbackfee") + " " +
- _("This is the transaction fee you may pay when fee estimates are not available."));
- CWallet::fallbackFee = CFeeRate(nFeePerK);
- }
- if (gArgs.IsArgSet("-discardfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK))
- return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-discardfee") + " " +
- _("This is the transaction fee you may discard if change is smaller than dust at this level"));
- CWallet::m_discard_rate = CFeeRate(nFeePerK);
- }
- if (gArgs.IsArgSet("-paytxfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
- return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-paytxfee") + " " +
- _("This is the transaction fee you will pay if you send a transaction."));
-
- payTxFee = CFeeRate(nFeePerK, 1000);
- if (payTxFee < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- if (gArgs.IsArgSet("-maxtxfee"))
- {
- CAmount nMaxFee = 0;
- if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
- if (nMaxFee > HIGH_MAX_TX_FEE)
- InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
- maxTxFee = nMaxFee;
- if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
- bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
- fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
-
- return true;
-}
-
bool CWallet::BackupWallet(const std::string& strDest)
{
return dbw->Backup(strDest);
@@ -4333,7 +4116,20 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
+bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
- return ::AcceptToMemoryPool(mempool, state, tx, true, nullptr, nullptr, false, nAbsurdFee);
+ // Quick check to avoid re-setting fInMempool to false
+ if (mempool.exists(tx->GetHash())) {
+ return false;
+ }
+
+ // We must set fInMempool here - while it will be re-set to true by the
+ // entered-mempool callback, if we did not there would be a race where a
+ // user could call sendmoney in a loop and hit spurious out of funds errors
+ // because we think that the transaction they just generated's change is
+ // unavailable as we're not yet aware its in mempool.
+ bool ret = ::AcceptToMemoryPool(mempool, state, tx, nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, nAbsurdFee);
+ fInMempool = ret;
+ return ret;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 963eb3de5f..97581794a8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -6,18 +6,18 @@
#ifndef BITCOIN_WALLET_WALLET_H
#define BITCOIN_WALLET_WALLET_H
-#include "amount.h"
-#include "policy/feerate.h"
-#include "streams.h"
-#include "tinyformat.h"
-#include "ui_interface.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "script/ismine.h"
-#include "script/sign.h"
-#include "wallet/crypter.h"
-#include "wallet/walletdb.h"
-#include "wallet/rpcwallet.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <streams.h>
+#include <tinyformat.h>
+#include <ui_interface.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <script/ismine.h>
+#include <script/sign.h>
+#include <wallet/crypter.h>
+#include <wallet/walletdb.h>
+#include <wallet/rpcwallet.h>
#include <algorithm>
#include <atomic>
@@ -65,8 +65,6 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
static const bool DEFAULT_WALLET_RBF = false;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
-//! if set, all keys will be derived by using BIP32
-static const bool DEFAULT_USE_HD_WALLET = true;
extern const char * DEFAULT_WALLET_DAT;
@@ -87,7 +85,7 @@ enum class FeeEstimateMode;
/** (client) version numbers for particular wallet features */
enum WalletFeature
{
- FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
+ FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output)
FEATURE_WALLETCRYPT = 40000, // wallet encryption
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
@@ -96,6 +94,8 @@ enum WalletFeature
FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k)
+ FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written
+
FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version
};
@@ -208,16 +208,12 @@ public:
Init();
}
- CMerkleTx(CTransactionRef arg)
+ explicit CMerkleTx(CTransactionRef arg)
{
SetTx(std::move(arg));
Init();
}
- /** Helper conversion operator to allow passing CMerkleTx where CTransaction is expected.
- * TODO: adapt callers and remove this operator. */
- operator const CTransaction&() const { return *tx; }
-
void Init()
{
hashBlock = uint256();
@@ -252,8 +248,6 @@ public:
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
- /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
@@ -330,6 +324,7 @@ public:
mutable bool fImmatureWatchCreditCached;
mutable bool fAvailableWatchCreditCached;
mutable bool fChangeCached;
+ mutable bool fInMempool;
mutable CAmount nDebitCached;
mutable CAmount nCreditCached;
mutable CAmount nImmatureCreditCached;
@@ -369,6 +364,7 @@ public:
fImmatureWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fChangeCached = false;
+ fInMempool = false;
nDebitCached = 0;
nCreditCached = 0;
nImmatureCreditCached = 0;
@@ -473,6 +469,9 @@ public:
// RelayWalletTransaction may only be called if fBroadcastTransactions!
bool RelayWalletTransaction(CConnman* connman);
+ /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
+
std::set<uint256> GetConflicts() const;
};
@@ -548,7 +547,7 @@ public:
//! todo: add something to note what created it (user, getnewaddress, change)
//! maybe should have a map<string, string> property map
- CWalletKey(int64_t nExpires=0);
+ explicit CWalletKey(int64_t nExpires=0);
ADD_SERIALIZE_METHODS;
@@ -651,7 +650,7 @@ private:
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet : public CCryptoKeyStore, public CValidationInterface
+class CWallet final : public CCryptoKeyStore, public CValidationInterface
{
private:
static std::atomic<bool> fFlushScheduled;
@@ -722,6 +721,18 @@ private:
std::unique_ptr<CWalletDBWrapper> dbw;
+ /**
+ * The following is used to keep track of how far behind the wallet is
+ * from the chain sync, and to allow clients to block on us being caught up.
+ *
+ * Note that this is *not* how far we've processed, we may need some rescan
+ * to have seen all transactions in the chain, but is only used to track
+ * live BlockConnected callbacks.
+ *
+ * Protected by cs_main (see BlockUntilSyncedToCurrentChain)
+ */
+ const CBlockIndex* m_last_block_processed;
+
public:
/*
* Main wallet lock.
@@ -750,9 +761,11 @@ public:
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
- // Map from Key ID (for regular keys) or Script ID (for watch-only keys) to
- // key metadata.
- std::map<CTxDestination, CKeyMetadata> mapKeyMetadata;
+ // Map from Key ID to key metadata.
+ std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
+
+ // Map from Script ID to key metadata (for watch-only keys).
+ std::map<CScriptID, CKeyMetadata> m_script_metadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@@ -765,7 +778,7 @@ public:
}
// Create wallet with passed-in database handle
- CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
+ explicit CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
{
SetNull();
}
@@ -807,8 +820,6 @@ public:
std::map<CTxDestination, CAddressBookData> mapAddressBook;
- CPubKey vchDefaultKey;
-
std::set<COutPoint> setLockedCoins;
const CWalletTx* GetWalletTx(const uint256& hash) const;
@@ -865,7 +876,8 @@ public:
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
- bool LoadKeyMetadata(const CTxDestination& pubKey, const CKeyMetadata &metadata);
+ bool LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);
+ bool LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
void UpdateTimeFirstKey(int64_t nCreateTime);
@@ -921,7 +933,8 @@ public:
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int64_t RescanFromTime(int64_t startTime, bool update);
- CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+ CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
+ void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
@@ -960,16 +973,6 @@ public:
static CFeeRate minTxFee;
static CFeeRate fallbackFee;
static CFeeRate m_discard_rate;
- /**
- * Estimate the minimum fee considering user set parameters
- * and the required fee
- */
- static CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
- /**
- * Return the minimum required fee taking into account the
- * floating relay fee and user set minimum transaction fee
- */
- static CAmount GetRequiredFee(unsigned int nTxBytes);
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
@@ -984,8 +987,6 @@ public:
*/
void MarkReserveKeysAsUsed(int64_t keypool_id);
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
- /** Does the wallet have at least min_keys in the keypool? */
- bool HasUnusedKeys(int min_keys) const;
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
@@ -1040,8 +1041,6 @@ public:
return setInternalKeyPool.size() + setExternalKeyPool.size();
}
- bool SetDefaultKey(const CPubKey &vchPubKey);
-
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);
@@ -1060,11 +1059,6 @@ public:
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
- //! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
- // This function will perform salvage on the wallet if requested, as long as only one wallet is
- // being loaded (CWallet::ParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
- static bool Verify();
-
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
@@ -1101,12 +1095,8 @@ public:
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
- /* Returns the wallets help message */
- static std::string GetWalletHelpString(bool showDebug);
-
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static CWallet* CreateWalletFromFile(const std::string walletFile);
- static bool InitLoadWallet();
/**
* Wallet post-init setup
@@ -1114,9 +1104,6 @@ public:
*/
void postInitProcess(CScheduler& scheduler);
- /* Wallets parameter interaction */
- static bool ParameterInteraction();
-
bool BackupWallet(const std::string& strDest);
/* Set the HD chain model (chain child index counters) */
@@ -1134,10 +1121,18 @@ public:
caller must ensure the current wallet version is correct before calling
this function). */
bool SetHDMasterKey(const CPubKey& key);
+
+ /**
+ * Blocks until the wallet state is up-to-date to /at least/ the current
+ * chain at the time this function is entered
+ * Obviously holding cs_main/cs_wallet when going into this call may cause
+ * deadlock
+ */
+ void BlockUntilSyncedToCurrentChain();
};
/** A key allocated from the key pool. */
-class CReserveKey : public CReserveScript
+class CReserveKey final : public CReserveScript
{
protected:
CWallet* pwallet;
@@ -1145,7 +1140,7 @@ protected:
CPubKey vchPubKey;
bool fInternal;
public:
- CReserveKey(CWallet* pwalletIn)
+ explicit CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 72c22d2259..efc50f72eb 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -3,18 +3,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/walletdb.h"
-
-#include "base58.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "protocol.h"
-#include "serialize.h"
-#include "sync.h"
-#include "util.h"
-#include "utiltime.h"
-#include "wallet/wallet.h"
+#include <wallet/walletdb.h>
+
+#include <base58.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <protocol.h>
+#include <serialize.h>
+#include <sync.h>
+#include <util.h>
+#include <utiltime.h>
+#include <wallet/wallet.h>
#include <atomic>
@@ -41,9 +41,9 @@ bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& s
return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
}
-bool CWalletDB::ErasePurpose(const std::string& strPurpose)
+bool CWalletDB::ErasePurpose(const std::string& strAddress)
{
- return EraseIC(std::make_pair(std::string("purpose"), strPurpose));
+ return EraseIC(std::make_pair(std::string("purpose"), strAddress));
}
bool CWalletDB::WriteTx(const CWalletTx& wtx)
@@ -130,11 +130,6 @@ bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
return WriteIC(std::string("orderposnext"), nOrderPosNext);
}
-bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
-{
- return WriteIC(std::string("defaultkey"), vchPubKey);
-}
-
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
{
return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
@@ -258,13 +253,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
}
else if (strType == "purpose")
{
std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
}
else if (strType == "tx")
{
@@ -273,7 +268,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx;
ssValue >> wtx;
CValidationState state;
- if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
+ if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
return false;
// Undo serialize changes in 31600
@@ -428,31 +423,34 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
wss.fIsEncrypted = true;
}
- else if (strType == "keymeta" || strType == "watchmeta")
+ else if (strType == "keymeta")
{
- CTxDestination keyID;
- if (strType == "keymeta")
- {
- CPubKey vchPubKey;
- ssKey >> vchPubKey;
- keyID = vchPubKey.GetID();
- }
- else if (strType == "watchmeta")
- {
- CScript script;
- ssKey >> script;
- keyID = CScriptID(script);
- }
-
+ CPubKey vchPubKey;
+ ssKey >> vchPubKey;
CKeyMetadata keyMeta;
ssValue >> keyMeta;
wss.nKeyMeta++;
-
- pwallet->LoadKeyMetadata(keyID, keyMeta);
+ pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
+ }
+ else if (strType == "watchmeta")
+ {
+ CScript script;
+ ssKey >> script;
+ CKeyMetadata keyMeta;
+ ssValue >> keyMeta;
+ wss.nKeyMeta++;
+ pwallet->LoadScriptMetadata(CScriptID(script), keyMeta);
}
else if (strType == "defaultkey")
{
- ssValue >> pwallet->vchDefaultKey;
+ // We don't want or need the default key, but if there is one set,
+ // we want to make sure that it is valid so that we can detect corruption
+ CPubKey vchPubKey;
+ ssValue >> vchPubKey;
+ if (!vchPubKey.IsValid()) {
+ strErr = "Error reading wallet database: Default Key corrupt";
+ return false;
+ }
}
else if (strType == "pool")
{
@@ -491,7 +489,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strAddress;
ssKey >> strKey;
ssValue >> strValue;
- if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
+ if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
{
strErr = "Error reading wallet database: LoadDestData failed";
return false;
@@ -522,7 +520,6 @@ bool CWalletDB::IsKeyType(const std::string& strType)
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
- pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss;
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
@@ -565,7 +562,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
- if (IsKeyType(strType))
+ if (IsKeyType(strType) || strType == "defaultkey")
result = DB_CORRUPT;
else
{
@@ -621,7 +618,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
pwallet->laccentries.clear();
ListAccountCreditDebit("*", pwallet->laccentries);
for (CAccountingEntry& entry : pwallet->laccentries) {
- pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
+ pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry)));
}
return result;
@@ -813,14 +810,14 @@ bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDa
return true;
}
-bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
+bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walletDir, std::string& errorStr)
{
- return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
+ return CDB::VerifyEnvironment(walletFile, walletDir, errorStr);
}
-bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
+bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& walletDir, std::string& warningStr, std::string& errorStr)
{
- return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
+ return CDB::VerifyDatabaseFile(walletFile, walletDir, warningStr, errorStr, CWalletDB::Recover);
}
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index d78f143ebd..e815bcfeda 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_WALLET_WALLETDB_H
#define BITCOIN_WALLET_WALLETDB_H
-#include "amount.h"
-#include "primitives/transaction.h"
-#include "wallet/db.h"
-#include "key.h"
+#include <amount.h>
+#include <primitives/transaction.h>
+#include <wallet/db.h>
+#include <key.h>
#include <list>
#include <stdint.h>
@@ -105,7 +105,7 @@ public:
{
SetNull();
}
- CKeyMetadata(int64_t nCreateTime_)
+ explicit CKeyMetadata(int64_t nCreateTime_)
{
SetNull();
nCreateTime = nCreateTime_;
@@ -162,11 +162,13 @@ private:
}
public:
- CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
+ explicit CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
batch(dbw, pszMode, _fFlushOnClose),
m_dbw(dbw)
{
}
+ CWalletDB(const CWalletDB&) = delete;
+ CWalletDB& operator=(const CWalletDB&) = delete;
bool WriteName(const std::string& strAddress, const std::string& strName);
bool EraseName(const std::string& strAddress);
@@ -191,8 +193,6 @@ public:
bool WriteOrderPosNext(int64_t nOrderPosNext);
- bool WriteDefaultKey(const CPubKey& vchPubKey);
-
bool ReadPool(int64_t nPool, CKeyPool& keypool);
bool WritePool(int64_t nPool, const CKeyPool& keypool);
bool ErasePool(int64_t nPool);
@@ -226,9 +226,9 @@ public:
/* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
static bool IsKeyType(const std::string& strType);
/* verifies the database environment */
- static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
+ static bool VerifyEnvironment(const std::string& walletFile, const fs::path& walletDir, std::string& errorStr);
/* verifies the database file */
- static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr);
+ static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& walletDir, std::string& warningStr, std::string& errorStr);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
@@ -246,9 +246,6 @@ public:
private:
CDB batch;
CWalletDBWrapper& m_dbw;
-
- CWalletDB(const CWalletDB&);
- void operator=(const CWalletDB&);
};
//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
new file mode 100644
index 0000000000..fbb5215a51
--- /dev/null
+++ b/src/wallet/walletutil.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "wallet/walletutil.h"
+
+fs::path GetWalletDir()
+{
+ fs::path path;
+
+ if (gArgs.IsArgSet("-walletdir")) {
+ path = fs::system_complete(gArgs.GetArg("-walletdir", ""));
+ if (!fs::is_directory(path)) {
+ // If the path specified doesn't exist, we return the deliberately
+ // invalid empty string.
+ path = "";
+ }
+ } else {
+ path = GetDataDir();
+ // If a wallets directory exists, use that, otherwise default to GetDataDir
+ if (fs::is_directory(path / "wallets")) {
+ path /= "wallets";
+ }
+ }
+
+ return path;
+}
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
new file mode 100644
index 0000000000..a94f286a44
--- /dev/null
+++ b/src/wallet/walletutil.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_UTIL_H
+#define BITCOIN_WALLET_UTIL_H
+
+#include "util.h"
+
+//! Get the path of the wallet directory.
+fs::path GetWalletDir();
+
+#endif // BITCOIN_WALLET_UTIL_H
diff --git a/src/warnings.cpp b/src/warnings.cpp
index d4e33b701a..c52a1fdb47 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sync.h"
-#include "clientversion.h"
-#include "util.h"
-#include "warnings.h"
+#include <sync.h>
+#include <clientversion.h>
+#include <util.h>
+#include <warnings.h>
CCriticalSection cs_warnings;
std::string strMiscWarning;
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 9f5cb3ba67..ce5c753eb4 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "zmqabstractnotifier.h"
-#include "util.h"
+#include <zmq/zmqabstractnotifier.h>
+#include <util.h>
CZMQAbstractNotifier::~CZMQAbstractNotifier()
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 77cf5141e2..6fbaba2036 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-#include "zmqconfig.h"
+#include <zmq/zmqconfig.h>
class CBlockIndex;
class CZMQAbstractNotifier;
@@ -15,7 +15,7 @@ typedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();
class CZMQAbstractNotifier
{
public:
- CZMQAbstractNotifier() : psocket(0) { }
+ CZMQAbstractNotifier() : psocket(nullptr) { }
virtual ~CZMQAbstractNotifier();
template <typename T>
diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h
index 610d7fbda4..ce8f3e13db 100644
--- a/src/zmq/zmqconfig.h
+++ b/src/zmq/zmqconfig.h
@@ -6,7 +6,7 @@
#define BITCOIN_ZMQ_ZMQCONFIG_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdarg.h>
@@ -16,8 +16,8 @@
#include <zmq.h>
#endif
-#include "primitives/block.h"
-#include "primitives/transaction.h"
+#include <primitives/block.h>
+#include <primitives/transaction.h>
void zmqError(const char *str);
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index c410cc269f..b663615752 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "zmqnotificationinterface.h"
-#include "zmqpublishnotifier.h"
+#include <zmq/zmqnotificationinterface.h>
+#include <zmq/zmqpublishnotifier.h>
-#include "version.h"
-#include "validation.h"
-#include "streams.h"
-#include "util.h"
+#include <version.h>
+#include <validation.h>
+#include <streams.h>
+#include <util.h>
void zmqError(const char *str)
{
@@ -40,15 +40,15 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
- for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
+ for (const auto& entry : factories)
{
- std::string arg("-zmq" + i->first);
+ std::string arg("-zmq" + entry.first);
if (gArgs.IsArgSet(arg))
{
- CZMQNotifierFactory factory = i->second;
+ CZMQNotifierFactory factory = entry.second;
std::string address = gArgs.GetArg(arg, "");
CZMQAbstractNotifier *notifier = factory();
- notifier->SetType(i->first);
+ notifier->SetType(entry.first);
notifier->SetAddress(address);
notifiers.push_back(notifier);
}
@@ -120,7 +120,7 @@ void CZMQNotificationInterface::Shutdown()
}
zmq_ctx_destroy(pcontext);
- pcontext = 0;
+ pcontext = nullptr;
}
}
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index eec6f7bc64..222d31e2ad 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
#define BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
-#include "validationinterface.h"
+#include <validationinterface.h>
#include <string>
#include <map>
#include <list>
@@ -13,7 +13,7 @@
class CBlockIndex;
class CZMQAbstractNotifier;
-class CZMQNotificationInterface : public CValidationInterface
+class CZMQNotificationInterface final : public CValidationInterface
{
public:
virtual ~CZMQNotificationInterface();
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 700c39f66e..acccb896c0 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "streams.h"
-#include "zmqpublishnotifier.h"
-#include "validation.h"
-#include "util.h"
-#include "rpc/server.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <streams.h>
+#include <zmq/zmqpublishnotifier.h>
+#include <validation.h>
+#include <util.h>
+#include <rpc/server.h>
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
@@ -126,7 +126,7 @@ void CZMQAbstractPublishNotifier::Shutdown()
zmq_close(psocket);
}
- psocket = 0;
+ psocket = nullptr;
}
bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)
@@ -136,7 +136,7 @@ bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* d
/* send three parts, command & data & a LE 4byte sequence number */
unsigned char msgseq[sizeof(uint32_t)];
WriteLE32(&msgseq[0], nSequence);
- int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), (void*)0);
+ int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), nullptr);
if (rc == -1)
return false;
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 1790fe5698..0e9bb23e5b 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
#define BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
-#include "zmqabstractnotifier.h"
+#include <zmq/zmqabstractnotifier.h>
class CBlockIndex;